From: Richard Smith Date: Wed, 7 Nov 2012 01:14:25 +0000 (+0000) Subject: PR11851 (and duplicates): Whenever a constexpr function is referenced, X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e10d304d204f6c5f4f280019f97b66227cb43162;p=platform%2Fupstream%2Fllvm.git 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. llvm-svn: 167514 --- diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 109386d..28a6371 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10340,15 +10340,44 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) { 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(Func); + if (!Func->isImplicitlyInstantiable() && (!MD || MD->isUserProvided())) + return; + } // Note that this declaration has been used. if (CXXConstructorDecl *Constructor = dyn_cast(Func)) { diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index a080031..8e8580d 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -2923,8 +2923,6 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType, case OR_Success: { // Record the standard conversion we used and the conversion function. CXXConstructorDecl *Constructor = cast(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 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, // Record the standard conversion we used and the conversion function. if (CXXConstructorDecl *Constructor = dyn_cast(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 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, } if (CXXConversionDecl *Conversion = dyn_cast(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 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, 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 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, Fn = Resolver.getMatchingFunctionDecl(); assert(Fn); FoundResult = *Resolver.getMatchingFunctionAccessPair(); - MarkFunctionReferenced(AddressOfExpr->getLocStart(), Fn); if (Complain) CheckAddressOfMemberAccess(AddressOfExpr, FoundResult); } diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index 0dd7ffe..f504eb6 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -1451,6 +1451,7 @@ namespace PR14203 { } // 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())}); } diff --git a/clang/test/SemaCXX/implicit-exception-spec.cpp b/clang/test/SemaCXX/implicit-exception-spec.cpp index b29cff5..e26f985 100644 --- a/clang/test/SemaCXX/implicit-exception-spec.cpp +++ b/clang/test/SemaCXX/implicit-exception-spec.cpp @@ -30,20 +30,17 @@ namespace InClassInitializers { 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::f(); - } inner; // expected-error {{cannot be used by non-static data member initializer}} + int n = ExceptionIf::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::f(); + int n = ExceptionIf::f(); } inner; }; } diff --git a/clang/test/SemaTemplate/constexpr-instantiate.cpp b/clang/test/SemaTemplate/constexpr-instantiate.cpp index 2f9fe0e..80c4aaf 100644 --- a/clang/test/SemaTemplate/constexpr-instantiate.cpp +++ b/clang/test/SemaTemplate/constexpr-instantiate.cpp @@ -75,3 +75,136 @@ namespace Reference { constexpr int n = const_cast(S::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 struct S { + S() : n(0) {} + S(const S&) : n(T::error) {} + int n; + }; + struct U : S {}; + decltype(U(U())) u; // ok, don't instantiate S::S() because it wasn't declared constexpr + } + namespace Constexpr { + template struct S { + constexpr S() : n(0) {} + constexpr S(const S&) : n(T::error) {} // expected-error {{has no members}} + int n; + }; + struct U : S {}; // expected-note {{instantiation}} + decltype(U(U())) u; // expected-note {{here}} + } + + namespace PR11851_Comment0 { + template constexpr int f() { return x; } + template void ovf(int (&x)[f()]); + void f() { int x[10]; ovf<10>(x); } + } + + namespace PR11851_Comment1 { + template + constexpr bool Integral() { + return true; + } + template()> + struct safe_make_unsigned { + typedef T type; + }; + template + using Make_unsigned = typename safe_make_unsigned::type; + template + struct get_distance_type { + using type = int; + }; + template + auto size(R) -> Make_unsigned::type>; + auto check() -> decltype(size(0)); + } + + namespace PR11851_Comment6 { + template struct foo {}; + template constexpr int bar() { return 0; } + template foo()> foobar(); + auto foobar_ = foobar(); + } + + 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 constexpr bool foo() { return true; } + template struct bar {}; + template bar()> baz() { return bar()>(); } + int main() { baz(); } + } + + namespace PR13423 { + template struct enable_if {}; + template struct enable_if { using type = T; }; + + template struct F { + template + static constexpr bool f() { return sizeof(T) < U::size; } + + template + static typename enable_if(), void>::type g() {} // expected-note {{disabled by 'enable_if'}} + }; + + struct U { static constexpr int size = 2; }; + + void h() { F::g(); } + void i() { F::g(); } // expected-error {{no matching function}} + } + + namespace PR14203 { + struct duration { constexpr duration() {} }; + + template + 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 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}} +}