Commit eab5474f by Nathan Sidwell Committed by Nathan Sidwell

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
parent ecd4a73b
2002-12-26 Nathan Sidwell <nathan@codesourcery.com> 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 PR c++/5116, c++/764
* call.c (build_new_op): Make sure template class operands are * call.c (build_new_op): Make sure template class operands are
instantiated. instantiated.
......
...@@ -2791,12 +2791,13 @@ finish_file () ...@@ -2791,12 +2791,13 @@ finish_file ()
reconsider = 1; reconsider = 1;
} }
/* Go through the various inline functions, and see if any need
synthesizing. */
for (i = 0; i < deferred_fns_used; ++i) for (i = 0; i < deferred_fns_used; ++i)
{ {
tree decl = VARRAY_TREE (deferred_fns, i); tree decl = VARRAY_TREE (deferred_fns, i);
import_export_decl (decl); import_export_decl (decl);
/* Does it need synthesizing? */
if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl) if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
&& TREE_USED (decl) && TREE_USED (decl)
&& (! DECL_REALLY_EXTERN (decl) || DECL_INLINE (decl))) && (! DECL_REALLY_EXTERN (decl) || DECL_INLINE (decl)))
...@@ -2811,30 +2812,21 @@ finish_file () ...@@ -2811,30 +2812,21 @@ finish_file ()
pop_from_top_level (); pop_from_top_level ();
reconsider = 1; reconsider = 1;
} }
}
/* We lie to the back-end, pretending that some functions are /* We lie to the back-end, pretending that some functions
not defined when they really are. This keeps these functions are not defined when they really are. This keeps these
from being put out unnecessarily. But, we must stop lying functions from being put out unnecessarily. But, we must
when the functions are referenced, or if they are not comdat stop lying when the functions are referenced, or if they
since they need to be put out now. are not comdat since they need to be put out now. This
This is done in a separate for cycle, because if some deferred is done in a separate for cycle, because if some deferred
function is contained in another deferred function later in function is contained in another deferred function later
deferred_fns varray, rest_of_compilation would skip this in deferred_fns varray, rest_of_compilation would skip
function and we really cannot expand the same function twice. */ this function and we really cannot expand the same
for (i = 0; i < deferred_fns_used; ++i) function twice. */
{
tree decl = VARRAY_TREE (deferred_fns, i);
if (DECL_NOT_REALLY_EXTERN (decl) if (DECL_NOT_REALLY_EXTERN (decl)
&& DECL_INITIAL (decl) && DECL_INITIAL (decl)
&& DECL_NEEDED_P (decl)) && DECL_NEEDED_P (decl))
DECL_EXTERNAL (decl) = 0; 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 /* If we're going to need to write this function out, and
there's already a body for it, create RTL for it now. there's already a body for it, create RTL for it now.
...@@ -2890,6 +2882,16 @@ finish_file () ...@@ -2890,6 +2882,16 @@ finish_file ()
} }
while (reconsider); 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. */ /* We give C linkage to static constructors and destructors. */
push_lang_context (lang_name_c); push_lang_context (lang_name_c);
...@@ -4665,6 +4667,12 @@ mark_used (decl) ...@@ -4665,6 +4667,12 @@ mark_used (decl)
TREE_USED (decl) = 1; TREE_USED (decl) = 1;
if (processing_template_decl) if (processing_template_decl)
return; 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) if (!skip_evaluation)
assemble_external (decl); assemble_external (decl);
......
...@@ -344,6 +344,8 @@ make_thunk (tree function, bool this_adjusting, ...@@ -344,6 +344,8 @@ make_thunk (tree function, bool this_adjusting,
DECL_NO_STATIC_CHAIN (thunk) = 1; DECL_NO_STATIC_CHAIN (thunk) = 1;
/* The THUNK is not a pending inline, even if the FUNCTION is. */ /* The THUNK is not a pending inline, even if the FUNCTION is. */
DECL_PENDING_INLINE_P (thunk) = 0; DECL_PENDING_INLINE_P (thunk) = 0;
DECL_INLINE (thunk) = 0;
DECL_DECLARED_INLINE_P (thunk) = 0;
/* Nor has it been deferred. */ /* Nor has it been deferred. */
DECL_DEFERRED_FN (thunk) = 0; DECL_DEFERRED_FN (thunk) = 0;
/* Add it to the list of thunks associated with FUNCTION. */ /* Add it to the list of thunks associated with FUNCTION. */
......
2002-12-26 Nathan Sidwell <nathan@codesourcery.com> 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/friend10.C: New test.
* g++.dg/template/conv5.C: New test. * g++.dg/template/conv5.C: New test.
......
// { 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; ...@@ -4,8 +4,8 @@ typedef long unsigned int size_t;
typedef void (*RF_Ptr)(void *); typedef void (*RF_Ptr)(void *);
struct _im_pers_mem_spec { struct _im_pers_mem_spec {
inline _im_pers_mem_spec(void ); _im_pers_mem_spec(void );
inline _im_pers_mem_spec(auto int of, auto int n); _im_pers_mem_spec(auto int of, auto int n);
}; };
struct _type_desc { struct _type_desc {
......
...@@ -7,14 +7,14 @@ class A; ...@@ -7,14 +7,14 @@ class A;
class AH class AH
{ {
public: public:
inline AH ( A * p = 0 ); AH ( A * p = 0 );
AH ( const AH & from ) AH ( const AH & from )
: pointer( from.pointer ) { inc(); } : pointer( from.pointer ) { inc(); }
~ AH () { dec(); } ~ AH () { dec(); }
private: private:
A * pointer; A * pointer;
inline void inc() const; void inc() const;
inline void dec() const; void dec() const;
}; };
class A class A
......
...@@ -13,7 +13,7 @@ class foo_b { ...@@ -13,7 +13,7 @@ class foo_b {
foo_b(); foo_b();
~foo_b(); ~foo_b();
foo_b(const foo_b&); foo_b(const foo_b&);
inline double& operator()(int); double& operator()(int);
foo_b& operator=(foo_b&); foo_b& operator=(foo_b&);
void bar_a(int); void bar_a(int);
}; };
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
class B { class B {
public: public:
inline ~B(); ~B();
}; };
class D : public B { class D : public B {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment