Hi Richard, This is still failing. :-)
-bw On Nov 11, 2012, at 12:43 AM, Bill Wendling <[email protected]> wrote: > Hi Richard, > > I think there might be a failure in the clang-tests GCC test suite that is > caused by this. The one that's failing is 'g++.dg/overload/addr1.C'. This is > the error I get on Darwin: > > $ clang++ -o /tmp/a.out addr1.C > Undefined symbols for architecture x86_64: > "A<int>::bar()", referenced from: > boz() in addr1-5Be2dG.o > ld: symbol(s) not found for architecture x86_64 > clang: error: linker command failed with exit code 1 (use -v to see > invocation) > > Here's the program: > > // Origin: Volker Reichelt <[email protected]> > > > > // PR c++/11788 we failed to instantiate a decl, and we lost some side > > > // effects > > > > static int flag = 0; > > template <typename> struct A > { > A &active () { flag++; return *this; } > > static void foo() {} > > static void bar () {} > static void bar (int) {} > > int m; > }; > > void (*baz ()) () > { > A<int> a; > return &a.active ().foo; > } > > void (*boz ()) () > { > A<int> a; > return &a.active ().bar; > } > > int *buz () > { > A<int> a; > > return &a.active ().m; > } > > int main () > { > baz (); > boz (); > buz (); > > return flag != 3; > } > > > -bw > > On Nov 6, 2012, at 5:14 PM, Richard Smith <[email protected]> wrote: > >> Author: rsmith >> Date: Tue Nov 6 19:14:25 2012 >> New Revision: 167514 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=167514&view=rev >> Log: >> PR11851 (and duplicates): Whenever a constexpr function is referenced, >> instantiate it if it can be instantiated and implicitly define it if it can >> be >> implicitly defined. This matches g++'s approach. Remove some cases from >> SemaOverload which were marking functions as referenced when just planning >> how >> overload resolution would proceed; such cases are not actually references. >> >> Modified: >> cfe/trunk/lib/Sema/SemaExpr.cpp >> cfe/trunk/lib/Sema/SemaOverload.cpp >> cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp >> cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp >> cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp >> >> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=167514&r1=167513&r2=167514&view=diff >> ============================================================================== >> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) >> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Nov 6 19:14:25 2012 >> @@ -10340,15 +10340,44 @@ >> >> Func->setReferenced(); >> >> - // Don't mark this function as used multiple times, unless it's a >> constexpr >> - // function which we need to instantiate. >> - if (Func->isUsed(false) && >> - !(Func->isConstexpr() && !Func->getBody() && >> - Func->isImplicitlyInstantiable())) >> - return; >> - >> - if (!IsPotentiallyEvaluatedContext(*this)) >> - return; >> + // C++11 [basic.def.odr]p3: >> + // A function whose name appears as a potentially-evaluated expression >> is >> + // odr-used if it is the unique lookup result or the selected member of >> a >> + // set of overloaded functions [...]. >> + // >> + // We (incorrectly) mark overload resolution as an unevaluated context, >> so we >> + // can just check that here. Skip the rest of this function if we've >> already >> + // marked the function as used. >> + if (Func->isUsed(false) || !IsPotentiallyEvaluatedContext(*this)) { >> + // C++11 [temp.inst]p3: >> + // Unless a function template specialization has been explicitly >> + // instantiated or explicitly specialized, the function template >> + // specialization is implicitly instantiated when the specialization >> is >> + // referenced in a context that requires a function definition to >> exist. >> + // >> + // We consider constexpr function templates to be referenced in a >> context >> + // that requires a definition to exist whenever they are referenced. >> + // >> + // FIXME: This instantiates constexpr functions too frequently. If this >> is >> + // really an unevaluated context (and we're not just in the definition >> of a >> + // function template or overload resolution or other cases which we >> + // incorrectly consider to be unevaluated contexts), and we're not in a >> + // subexpression which we actually need to evaluate (for instance, a >> + // template argument, array bound or an expression in a >> braced-init-list), >> + // we are not permitted to instantiate this constexpr function >> definition. >> + // >> + // FIXME: This also implicitly defines special members too frequently. >> They >> + // are only supposed to be implicitly defined if they are odr-used, but >> they >> + // are not odr-used from constant expressions in unevaluated contexts. >> + // However, they cannot be referenced if they are deleted, and they are >> + // deleted whenever the implicit definition of the special member would >> + // fail. >> + if (!Func->isConstexpr() || Func->getBody()) >> + return; >> + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func); >> + if (!Func->isImplicitlyInstantiable() && (!MD || MD->isUserProvided())) >> + return; >> + } >> >> // Note that this declaration has been used. >> if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) { >> >> Modified: cfe/trunk/lib/Sema/SemaOverload.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=167514&r1=167513&r2=167514&view=diff >> ============================================================================== >> --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) >> +++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Nov 6 19:14:25 2012 >> @@ -2923,8 +2923,6 @@ >> case OR_Success: { >> // Record the standard conversion we used and the conversion function. >> CXXConstructorDecl *Constructor = >> cast<CXXConstructorDecl>(Best->Function); >> - S.MarkFunctionReferenced(From->getLocStart(), Constructor); >> - >> QualType ThisType = Constructor->getThisType(S.Context); >> // Initializer lists don't have conversions as such. >> User.Before.setAsIdentityConversion(); >> @@ -3105,8 +3103,6 @@ >> // Record the standard conversion we used and the conversion function. >> if (CXXConstructorDecl *Constructor >> = dyn_cast<CXXConstructorDecl>(Best->Function)) { >> - S.MarkFunctionReferenced(From->getLocStart(), Constructor); >> - >> // C++ [over.ics.user]p1: >> // If the user-defined conversion is specified by a >> // constructor (12.3.1), the initial standard conversion >> @@ -3135,8 +3131,6 @@ >> } >> if (CXXConversionDecl *Conversion >> = dyn_cast<CXXConversionDecl>(Best->Function)) { >> - S.MarkFunctionReferenced(From->getLocStart(), Conversion); >> - >> // C++ [over.ics.user]p1: >> // >> // [...] If the user-defined conversion is specified by a >> @@ -4049,8 +4043,6 @@ >> if (!Best->FinalConversion.DirectBinding) >> return false; >> >> - if (Best->Function) >> - S.MarkFunctionReferenced(DeclLoc, Best->Function); >> ICS.setUserDefined(); >> ICS.UserDefined.Before = Best->Conversions[0].Standard; >> ICS.UserDefined.After = Best->FinalConversion; >> @@ -9225,7 +9217,6 @@ >> Fn = Resolver.getMatchingFunctionDecl(); >> assert(Fn); >> FoundResult = *Resolver.getMatchingFunctionAccessPair(); >> - MarkFunctionReferenced(AddressOfExpr->getLocStart(), Fn); >> if (Complain) >> CheckAddressOfMemberAccess(AddressOfExpr, FoundResult); >> } >> >> Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=167514&r1=167513&r2=167514&view=diff >> ============================================================================== >> --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original) >> +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Tue Nov 6 19:14:25 >> 2012 >> @@ -1451,6 +1451,7 @@ >> } >> // FIXME: It's unclear whether this is valid. On the one hand, we're not >> // allowed to generate a move constructor. On the other hand, if we did, >> - // this would be a constant expression. >> - int n = sizeof(short{duration(duration())}); // expected-error >> {{non-constant-expression cannot be narrowed}} expected-note {{override}} >> + // this would be a constant expression. For now, we generate a move >> + // constructor here. >> + int n = sizeof(short{duration(duration())}); >> } >> >> Modified: cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp?rev=167514&r1=167513&r2=167514&view=diff >> ============================================================================== >> --- cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp (original) >> +++ cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp Tue Nov 6 19:14:25 >> 2012 >> @@ -30,20 +30,17 @@ >> bool x = noexcept(TemplateArg()); >> >> // And within a nested class. >> - // FIXME: The diagnostic location is terrible here. >> - struct Nested { >> + struct Nested { // expected-error {{cannot be used by non-static data >> member initializer}} >> struct Inner { >> - int n = ExceptionIf<noexcept(Nested())>::f(); >> - } inner; // expected-error {{cannot be used by non-static data member >> initializer}} >> + int n = ExceptionIf<noexcept(Nested())>::f(); // expected-note >> {{implicit default constructor for 'InClassInitializers::Nested' first >> required here}} >> + } inner; >> }; >> - bool y = noexcept(Nested()); >> - bool z = noexcept(Nested::Inner()); >> >> struct Nested2 { >> struct Inner; >> int n = Inner().n; // expected-error {{cannot be used by non-static data >> member initializer}} >> struct Inner { >> - int n = ExceptionIf<noexcept(Nested())>::f(); >> + int n = ExceptionIf<noexcept(Nested2())>::f(); >> } inner; >> }; >> } >> >> Modified: cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp?rev=167514&r1=167513&r2=167514&view=diff >> ============================================================================== >> --- cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp (original) >> +++ cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp Tue Nov 6 >> 19:14:25 2012 >> @@ -75,3 +75,136 @@ >> constexpr int n = const_cast<int&>(S<int>::r); >> static_assert(n == 5, ""); >> } >> + >> +namespace Unevaluated { >> + // We follow g++ in treating any reference to a constexpr function >> template >> + // specialization as requiring an instantiation, even if it occurs in an >> + // unevaluated context. >> + // >> + // We go slightly further than g++, and also trigger the implicit >> definition >> + // of a defaulted special member in the same circumstances. This seems >> scary, >> + // since a lot of classes have constexpr special members in C++11, but the >> + // only observable impact should be the implicit instantiation of >> constexpr >> + // special member templates (defaulted special members should only be >> + // generated if they are well-formed, and non-constexpr special members >> in a >> + // base or member cause the class's special member to not be constexpr). >> + // >> + // FIXME: None of this is required by the C++ standard. The rules in this >> + // area are poorly specified, so this is subject to change. >> + namespace NotConstexpr { >> + template<typename T> struct S { >> + S() : n(0) {} >> + S(const S&) : n(T::error) {} >> + int n; >> + }; >> + struct U : S<int> {}; >> + decltype(U(U())) u; // ok, don't instantiate S<int>::S() because it >> wasn't declared constexpr >> + } >> + namespace Constexpr { >> + template<typename T> struct S { >> + constexpr S() : n(0) {} >> + constexpr S(const S&) : n(T::error) {} // expected-error {{has no >> members}} >> + int n; >> + }; >> + struct U : S<int> {}; // expected-note {{instantiation}} >> + decltype(U(U())) u; // expected-note {{here}} >> + } >> + >> + namespace PR11851_Comment0 { >> + template<int x> constexpr int f() { return x; } >> + template<int i> void ovf(int (&x)[f<i>()]); >> + void f() { int x[10]; ovf<10>(x); } >> + } >> + >> + namespace PR11851_Comment1 { >> + template<typename T> >> + constexpr bool Integral() { >> + return true; >> + } >> + template<typename T, bool Int = Integral<T>()> >> + struct safe_make_unsigned { >> + typedef T type; >> + }; >> + template<typename T> >> + using Make_unsigned = typename safe_make_unsigned<T>::type; >> + template <typename T> >> + struct get_distance_type { >> + using type = int; >> + }; >> + template<typename R> >> + auto size(R) -> Make_unsigned<typename get_distance_type<R>::type>; >> + auto check() -> decltype(size(0)); >> + } >> + >> + namespace PR11851_Comment6 { >> + template<int> struct foo {}; >> + template<class> constexpr int bar() { return 0; } >> + template<class T> foo<bar<T>()> foobar(); >> + auto foobar_ = foobar<int>(); >> + } >> + >> + namespace PR11851_Comment9 { >> + struct S1 { >> + constexpr S1() {} >> + constexpr operator int() const { return 0; } >> + }; >> + int k1 = sizeof(short{S1(S1())}); >> + >> + struct S2 { >> + constexpr S2() {} >> + constexpr operator int() const { return 123456; } >> + }; >> + int k2 = sizeof(short{S2(S2())}); // expected-error {{cannot be >> narrowed}} expected-note {{override}} >> + } >> + >> + namespace PR12288 { >> + template <typename> constexpr bool foo() { return true; } >> + template <bool> struct bar {}; >> + template <typename T> bar<foo<T>()> baz() { return bar<foo<T>()>(); } >> + int main() { baz<int>(); } >> + } >> + >> + namespace PR13423 { >> + template<bool, typename> struct enable_if {}; >> + template<typename T> struct enable_if<true, T> { using type = T; }; >> + >> + template<typename T> struct F { >> + template<typename U> >> + static constexpr bool f() { return sizeof(T) < U::size; } >> + >> + template<typename U> >> + static typename enable_if<f<U>(), void>::type g() {} // expected-note >> {{disabled by 'enable_if'}} >> + }; >> + >> + struct U { static constexpr int size = 2; }; >> + >> + void h() { F<char>::g<U>(); } >> + void i() { F<int>::g<U>(); } // expected-error {{no matching function}} >> + } >> + >> + namespace PR14203 { >> + struct duration { constexpr duration() {} }; >> + >> + template <typename> >> + void sleep_for() { >> + constexpr duration max = duration(); >> + } >> + } >> +} >> + >> +namespace NoInstantiationWhenSelectingOverload { >> + // Check that we don't instantiate conversion functions when we're >> checking >> + // for the existence of an implicit conversion sequence, only when a >> function >> + // is actually chosen by overload resolution. >> + struct S { >> + template<typename T> constexpr S(T) : n(T::error) {} // expected-error >> {{no members}} >> + int n; >> + }; >> + >> + void f(S); >> + void f(int); >> + >> + void g() { f(0); } >> + void h() { (void)sizeof(f(0)); } >> + void i() { (void)sizeof(f("oops")); } // expected-note {{instantiation >> of}} >> +} >> >> >> _______________________________________________ >> cfe-commits mailing list >> [email protected] >> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
