[cfe-commits] r167514 - in /cfe/trunk: lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/constant-expression-cxx11.cpp test/SemaCXX/implicit-exception-spec.cpp test/SemaTemplate/constexpr-instantiate.cpp
Argyrios Kyrtzidis
kyrtzidis at apple.com
Wed Nov 14 13:00:52 PST 2012
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 <richard-llvm at metafoo.co.uk> 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
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list