[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
Richard Smith
richard at metafoo.co.uk
Tue Nov 13 23:08:03 PST 2012
On Tue, Nov 13, 2012 at 9:50 PM, Bill Wendling <wendling at apple.com> 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 <wendling at apple.com> 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 <reichelt at igpm.rwth-aachen.de>
>>
>> // 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 <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
>>
>> _______________________________________________
>> 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