Hi Richard, I think this caused a regression, could you take a look at http://llvm.org/bugs/show_bug.cgi?id=14340 ?
-Argyrios 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
