On Tue, Nov 13, 2012 at 9:50 PM, Bill Wendling <[email protected]> wrote: > Hi Richard, > > This is still failing. :-)
Thanks for the reminder. Fixed in r167918. > -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
