mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-02-06 10:09:57 +08:00
re PR c++/4803 (Inline function never defined)
cp: PR c++/4803 * decl2.c (mark_used): Defer inline functions. (finish_file): Merge deferred_fns loops. Check all used inline functions have a definition. * method.c (make_thunk): Thunks are not inline. testsuite: * g++.dg/warn/inline1.C: New test. * g++.old-deja/g++.brendan/crash64.C: Remove spurious inlines. * g++.old-deja/g++.jason/synth10.C: Likewise. * g++.old-deja/g++.mike/net31.C: Likewise. * g++.old-deja/g++.mike/p8786.C: Likewise. From-SVN: r60521
This commit is contained in:
parent
ecd4a73b20
commit
eab5474f6d
@ -1,5 +1,11 @@
|
||||
2002-12-26 Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
PR c++/4803
|
||||
* decl2.c (mark_used): Defer inline functions.
|
||||
(finish_file): Merge deferred_fns loops. Check all used
|
||||
inline functions have a definition.
|
||||
* method.c (make_thunk): Thunks are not inline.
|
||||
|
||||
PR c++/5116, c++/764
|
||||
* call.c (build_new_op): Make sure template class operands are
|
||||
instantiated.
|
||||
|
@ -2791,12 +2791,13 @@ finish_file ()
|
||||
reconsider = 1;
|
||||
}
|
||||
|
||||
/* Go through the various inline functions, and see if any need
|
||||
synthesizing. */
|
||||
for (i = 0; i < deferred_fns_used; ++i)
|
||||
{
|
||||
tree decl = VARRAY_TREE (deferred_fns, i);
|
||||
|
||||
import_export_decl (decl);
|
||||
|
||||
/* Does it need synthesizing? */
|
||||
if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
|
||||
&& TREE_USED (decl)
|
||||
&& (! DECL_REALLY_EXTERN (decl) || DECL_INLINE (decl)))
|
||||
@ -2811,30 +2812,21 @@ finish_file ()
|
||||
pop_from_top_level ();
|
||||
reconsider = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* We lie to the back-end, pretending that some functions are
|
||||
not defined when they really are. This keeps these functions
|
||||
from being put out unnecessarily. But, we must stop lying
|
||||
when the functions are referenced, or if they are not comdat
|
||||
since they need to be put out now.
|
||||
This is done in a separate for cycle, because if some deferred
|
||||
function is contained in another deferred function later in
|
||||
deferred_fns varray, rest_of_compilation would skip this
|
||||
function and we really cannot expand the same function twice. */
|
||||
for (i = 0; i < deferred_fns_used; ++i)
|
||||
{
|
||||
tree decl = VARRAY_TREE (deferred_fns, i);
|
||||
|
||||
/* We lie to the back-end, pretending that some functions
|
||||
are not defined when they really are. This keeps these
|
||||
functions from being put out unnecessarily. But, we must
|
||||
stop lying when the functions are referenced, or if they
|
||||
are not comdat since they need to be put out now. This
|
||||
is done in a separate for cycle, because if some deferred
|
||||
function is contained in another deferred function later
|
||||
in deferred_fns varray, rest_of_compilation would skip
|
||||
this function and we really cannot expand the same
|
||||
function twice. */
|
||||
if (DECL_NOT_REALLY_EXTERN (decl)
|
||||
&& DECL_INITIAL (decl)
|
||||
&& DECL_NEEDED_P (decl))
|
||||
DECL_EXTERNAL (decl) = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < deferred_fns_used; ++i)
|
||||
{
|
||||
tree decl = VARRAY_TREE (deferred_fns, i);
|
||||
|
||||
/* If we're going to need to write this function out, and
|
||||
there's already a body for it, create RTL for it now.
|
||||
@ -2890,6 +2882,16 @@ finish_file ()
|
||||
}
|
||||
while (reconsider);
|
||||
|
||||
/* All used inline functions must have a definition at this point. */
|
||||
for (i = 0; i < deferred_fns_used; ++i)
|
||||
{
|
||||
tree decl = VARRAY_TREE (deferred_fns, i);
|
||||
|
||||
if (TREE_USED (decl) && DECL_DECLARED_INLINE_P (decl)
|
||||
&& !(TREE_ASM_WRITTEN (decl) || DECL_SAVED_TREE (decl)))
|
||||
cp_warning_at ("inline function `%D' used but never defined", decl);
|
||||
}
|
||||
|
||||
/* We give C linkage to static constructors and destructors. */
|
||||
push_lang_context (lang_name_c);
|
||||
|
||||
@ -4665,6 +4667,12 @@ mark_used (decl)
|
||||
TREE_USED (decl) = 1;
|
||||
if (processing_template_decl)
|
||||
return;
|
||||
|
||||
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)
|
||||
&& !TREE_ASM_WRITTEN (decl))
|
||||
/* Remember it, so we can check it was defined. */
|
||||
defer_fn (decl);
|
||||
|
||||
if (!skip_evaluation)
|
||||
assemble_external (decl);
|
||||
|
||||
|
@ -344,6 +344,8 @@ make_thunk (tree function, bool this_adjusting,
|
||||
DECL_NO_STATIC_CHAIN (thunk) = 1;
|
||||
/* The THUNK is not a pending inline, even if the FUNCTION is. */
|
||||
DECL_PENDING_INLINE_P (thunk) = 0;
|
||||
DECL_INLINE (thunk) = 0;
|
||||
DECL_DECLARED_INLINE_P (thunk) = 0;
|
||||
/* Nor has it been deferred. */
|
||||
DECL_DEFERRED_FN (thunk) = 0;
|
||||
/* Add it to the list of thunks associated with FUNCTION. */
|
||||
|
@ -1,5 +1,11 @@
|
||||
2002-12-26 Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
* g++.dg/warn/inline1.C: New test.
|
||||
* g++.old-deja/g++.brendan/crash64.C: Remove spurious inlines.
|
||||
* g++.old-deja/g++.jason/synth10.C: Likewise.
|
||||
* g++.old-deja/g++.mike/net31.C: Likewise.
|
||||
* g++.old-deja/g++.mike/p8786.C: Likewise.
|
||||
|
||||
* g++.dg/template/friend10.C: New test.
|
||||
* g++.dg/template/conv5.C: New test.
|
||||
|
||||
|
23
gcc/testsuite/g++.dg/warn/inline1.C
Normal file
23
gcc/testsuite/g++.dg/warn/inline1.C
Normal file
@ -0,0 +1,23 @@
|
||||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
// Contributed by Nathan Sidwell 26 Dec 2002 <nathan@codesourcery.com>
|
||||
|
||||
// PR 4803. Used inline functions must have a definition.
|
||||
|
||||
inline void Foo1 (); // { dg-warning "inline function" "" }
|
||||
inline void Bar1 ();
|
||||
template <typename T> inline void Foo2(T); // { dg-warning "inline function" "" }
|
||||
template <typename T> inline void Bar2(T);
|
||||
|
||||
void Baz ()
|
||||
{
|
||||
Foo1 ();
|
||||
Foo2 (1);
|
||||
|
||||
Bar1 ();
|
||||
Bar2 (1);
|
||||
}
|
||||
|
||||
inline void Bar1 () {}
|
||||
template <typename T> inline void Bar2(T) {}
|
@ -4,8 +4,8 @@ typedef long unsigned int size_t;
|
||||
typedef void (*RF_Ptr)(void *);
|
||||
|
||||
struct _im_pers_mem_spec {
|
||||
inline _im_pers_mem_spec(void );
|
||||
inline _im_pers_mem_spec(auto int of, auto int n);
|
||||
_im_pers_mem_spec(void );
|
||||
_im_pers_mem_spec(auto int of, auto int n);
|
||||
};
|
||||
|
||||
struct _type_desc {
|
||||
|
@ -7,14 +7,14 @@ class A;
|
||||
class AH
|
||||
{
|
||||
public:
|
||||
inline AH ( A * p = 0 );
|
||||
AH ( A * p = 0 );
|
||||
AH ( const AH & from )
|
||||
: pointer( from.pointer ) { inc(); }
|
||||
~ AH () { dec(); }
|
||||
private:
|
||||
A * pointer;
|
||||
inline void inc() const;
|
||||
inline void dec() const;
|
||||
void inc() const;
|
||||
void dec() const;
|
||||
};
|
||||
|
||||
class A
|
||||
|
@ -13,7 +13,7 @@ class foo_b {
|
||||
foo_b();
|
||||
~foo_b();
|
||||
foo_b(const foo_b&);
|
||||
inline double& operator()(int);
|
||||
double& operator()(int);
|
||||
foo_b& operator=(foo_b&);
|
||||
void bar_a(int);
|
||||
};
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
class B {
|
||||
public:
|
||||
inline ~B();
|
||||
~B();
|
||||
};
|
||||
|
||||
class D : public B {
|
||||
|
Loading…
Reference in New Issue
Block a user