[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

Bill Wendling wendling at apple.com
Tue Nov 13 21:50:59 PST 2012


Hi Richard,

This is still failing. :-)

-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