diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2291b733b589..08177c091fa5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,11 @@ 2002-12-26 Nathan Sidwell + 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. diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 3d717e8475b9..1607e379090a 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 12a66f6526d6..e5a3bd974fb3 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -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. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a68ab21957b7..c54c1c2c1c0b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,11 @@ 2002-12-26 Nathan Sidwell + * 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. diff --git a/gcc/testsuite/g++.dg/warn/inline1.C b/gcc/testsuite/g++.dg/warn/inline1.C new file mode 100644 index 000000000000..24836e744ebb --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/inline1.C @@ -0,0 +1,23 @@ +// { dg-do compile } + +// Copyright (C) 2002 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 26 Dec 2002 + +// PR 4803. Used inline functions must have a definition. + +inline void Foo1 (); // { dg-warning "inline function" "" } +inline void Bar1 (); +template inline void Foo2(T); // { dg-warning "inline function" "" } +template inline void Bar2(T); + +void Baz () +{ + Foo1 (); + Foo2 (1); + + Bar1 (); + Bar2 (1); +} + +inline void Bar1 () {} +template inline void Bar2(T) {} diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash64.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash64.C index ccba22e245a9..6c2825802f46 100644 --- a/gcc/testsuite/g++.old-deja/g++.brendan/crash64.C +++ b/gcc/testsuite/g++.old-deja/g++.brendan/crash64.C @@ -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 { diff --git a/gcc/testsuite/g++.old-deja/g++.jason/synth10.C b/gcc/testsuite/g++.old-deja/g++.jason/synth10.C index d94e6bdebe96..07a372586c01 100644 --- a/gcc/testsuite/g++.old-deja/g++.jason/synth10.C +++ b/gcc/testsuite/g++.old-deja/g++.jason/synth10.C @@ -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 diff --git a/gcc/testsuite/g++.old-deja/g++.mike/net31.C b/gcc/testsuite/g++.old-deja/g++.mike/net31.C index 3ecf81c73491..05617a8b4ffd 100644 --- a/gcc/testsuite/g++.old-deja/g++.mike/net31.C +++ b/gcc/testsuite/g++.old-deja/g++.mike/net31.C @@ -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); }; diff --git a/gcc/testsuite/g++.old-deja/g++.mike/p8786.C b/gcc/testsuite/g++.old-deja/g++.mike/p8786.C index b5443c0fa6ba..0565fb2558a1 100644 --- a/gcc/testsuite/g++.old-deja/g++.mike/p8786.C +++ b/gcc/testsuite/g++.old-deja/g++.mike/p8786.C @@ -4,7 +4,7 @@ class B { public: - inline ~B(); + ~B(); }; class D : public B {