[cfe-commits] r154053 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp test/CodeGenCXX/mangle-template.cpp test/SemaCXX/cxx98-compat.cpp

Nico Weber thakis at chromium.org
Wed Apr 4 14:44:21 PDT 2012


Hi Richard,

(below)

On Wed, Apr 4, 2012 at 2:11 PM, Richard Smith
<richard-llvm at metafoo.co.uk> wrote:
> Author: rsmith
> Date: Wed Apr  4 16:11:30 2012
> New Revision: 154053
>
> URL: http://llvm.org/viewvc/llvm-project?rev=154053&view=rev
> Log:
> Implement C++11 [temp.arg.nontype]'s permission to use the address of an object
> or function with internal linkage as a non-type template argument.
>
> Modified:
>    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>    cfe/trunk/lib/Sema/SemaTemplate.cpp
>    cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
>    cfe/trunk/test/CodeGenCXX/mangle-template.cpp
>    cfe/trunk/test/SemaCXX/cxx98-compat.cpp
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=154053&r1=154052&r2=154053&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Apr  4 16:11:30 2012
> @@ -2361,11 +2361,18 @@
>   "non-type template argument refers to non-static data member %0">;
>  def err_template_arg_method : Error<
>   "non-type template argument refers to non-static member function %0">;
> -def err_template_arg_function_not_extern : Error<
> -  "non-type template argument refers to function %0 with internal linkage">;
> -def err_template_arg_object_not_extern : Error<
> -  "non-type template argument refers to object %0 that does not have external "
> -  "linkage">;
> +def err_template_arg_object_no_linkage : Error<
> +  "non-type template argument refers to %select{function|object}0 %1 that "
> +  "does not have linkage">;
> +def warn_cxx98_compat_template_arg_object_internal : Warning<
> +  "non-type template argument referring to %select{function|object}0 %1 with "
> +  "internal linkage is incompatible with C++98">,
> +  InGroup<CXX98Compat>, DefaultIgnore;
> +def ext_template_arg_object_internal : ExtWarn<
> +  "non-type template argument referring to %select{function|object}0 %1 with "
> +  "internal linkage is a C++11 extension">, InGroup<CXX11>;
> +def err_template_arg_thread_local : Error<
> +  "non-type template argument refers to thread-local object">;
>  def note_template_arg_internal_object : Note<
>   "non-type template argument refers to %select{function|object}0 here">;
>  def note_template_arg_refers_here : Note<
>
> Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=154053&r1=154052&r2=154053&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Apr  4 16:11:30 2012
> @@ -3550,10 +3550,10 @@
>     return true;
>   }
>
> -  NamedDecl *Entity = 0;
> +  NamedDecl *Entity = DRE->getDecl();
>
>   // Cannot refer to non-static data members
> -  if (FieldDecl *Field = dyn_cast<FieldDecl>(DRE->getDecl())) {
> +  if (FieldDecl *Field = dyn_cast<FieldDecl>(Entity)) {
>     S.Diag(Arg->getLocStart(), diag::err_template_arg_field)
>       << Field << Arg->getSourceRange();
>     S.Diag(Param->getLocation(), diag::note_template_param_here);
> @@ -3561,28 +3561,44 @@
>   }
>
>   // Cannot refer to non-static member functions
> -  if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(DRE->getDecl()))
> +  if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Entity)) {
>     if (!Method->isStatic()) {
>       S.Diag(Arg->getLocStart(), diag::err_template_arg_method)
>         << Method << Arg->getSourceRange();
>       S.Diag(Param->getLocation(), diag::note_template_param_here);
>       return true;
>     }
> +  }
>
> -  // Functions must have external linkage.
> -  if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) {
> -    if (!isExternalLinkage(Func->getLinkage())) {
> -      S.Diag(Arg->getLocStart(),
> -             diag::err_template_arg_function_not_extern)
> -        << Func << Arg->getSourceRange();
> -      S.Diag(Func->getLocation(), diag::note_template_arg_internal_object)
> -        << true;
> -      return true;
> -    }
> +  FunctionDecl *Func = dyn_cast<FunctionDecl>(Entity);
> +  VarDecl *Var = dyn_cast<VarDecl>(Entity);
> +
> +  // A non-type template argument must refer to an object or function.
> +  if (!Func && !Var) {
> +    // We found something, but we don't know specifically what it is.
> +    S.Diag(Arg->getLocStart(), diag::err_template_arg_not_object_or_func)
> +      << Arg->getSourceRange();
> +    S.Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here);
> +    return true;
> +  }
>
> -    // Okay: we've named a function with external linkage.
> -    Entity = Func;
> +  // Address / reference template args must have external linkage in C++98.
> +  if (Entity->getLinkage() == InternalLinkage) {
> +    S.Diag(Arg->getLocStart(), S.getLangOpts().CPlusPlus0x ?
> +             diag::warn_cxx98_compat_template_arg_object_internal :
> +             diag::ext_template_arg_object_internal)
> +      << !Func << Entity << Arg->getSourceRange();
> +    S.Diag(Entity->getLocation(), diag::note_template_arg_internal_object)
> +      << !Func;
> +  } else if (Entity->getLinkage() == NoLinkage) {
> +    S.Diag(Arg->getLocStart(), diag::err_template_arg_object_no_linkage)
> +      << !Func << Entity << Arg->getSourceRange();
> +    S.Diag(Entity->getLocation(), diag::note_template_arg_internal_object)
> +      << !Func;
> +    return true;
> +  }
>
> +  if (Func) {
>     // If the template parameter has pointer type, the function decays.
>     if (ParamType->isPointerType() && !AddressTaken)
>       ArgType = S.Context.getPointerType(Func->getType());
> @@ -3605,16 +3621,7 @@
>
>       ArgType = Func->getType();
>     }
> -  } else if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
> -    if (!isExternalLinkage(Var->getLinkage())) {
> -      S.Diag(Arg->getLocStart(),
> -             diag::err_template_arg_object_not_extern)
> -        << Var << Arg->getSourceRange();
> -      S.Diag(Var->getLocation(), diag::note_template_arg_internal_object)
> -        << true;
> -      return true;
> -    }
> -
> +  } else {
>     // A value of reference type is not an object.
>     if (Var->getType()->isReferenceType()) {
>       S.Diag(Arg->getLocStart(),
> @@ -3624,8 +3631,14 @@
>       return true;
>     }
>
> -    // Okay: we've named an object with external linkage
> -    Entity = Var;
> +    // A template argument must have static storage duration.
> +    // FIXME: Ensure this works for thread_local as well as __thread.
> +    if (Var->isThreadSpecified()) {
> +      S.Diag(Arg->getLocStart(), diag::err_template_arg_thread_local)
> +        << Arg->getSourceRange();
> +      S.Diag(Var->getLocation(), diag::note_template_arg_refers_here);
> +      return true;
> +    }
>
>     // If the template parameter has pointer type, we must have taken
>     // the address of this object.
> @@ -3672,13 +3685,6 @@
>         S.Diag(Param->getLocation(), diag::note_template_param_here);
>       }
>     }
> -  } else {
> -    // We found something else, but we don't know specifically what it is.
> -    S.Diag(Arg->getLocStart(),
> -           diag::err_template_arg_not_object_or_func)
> -      << Arg->getSourceRange();
> -    S.Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here);
> -    return true;
>   }
>
>   bool ObjCLifetimeConversion;
>
> Modified: cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp?rev=154053&r1=154052&r2=154053&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp (original)
> +++ cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp Wed Apr  4 16:11:30 2012
> @@ -1,6 +1,6 @@
>  // RUN: %clang_cc1 -fsyntax-only -verify %s
>
> -// C++0x [temp.arg.nontype]p1:
> +// C++11 [temp.arg.nontype]p1:
>  //
>  //   A template-argument for a non-type, non-template template-parameter shall
>  //   be one of:
> @@ -19,27 +19,65 @@
>   template <typename T, int (T::* M)(int)> X5<T, M>::X5() { }
>  }
>
> -//   -- the address of an object or function with external linkage, including
> -//      function templates and function template-ids but excluding non-static
> -//      class members, expressed as & id-expression where the & is optional if
> -//      the name refers to a function or array, or if the corresponding
> -//      template-parameter is a reference; or
> +//   -- a constant expression that designates the address of an object with
> +//      static storage duration and external or internal linkage or a function
> +//      with external or internal linkage, including function templates and
> +//      function template-ids, but excluting non-static class members, expressed
> +//      (ignoring parentheses) as & id-expression, except that the & may be
> +//      omitted if the name refers to a function or array and shall be omitted
> +//      if the corresopnding template-parameter is a reference; or
>  namespace addr_of_obj_or_func {
> -  template <int* p> struct X0 { };
> +  template <int* p> struct X0 { }; // expected-note 4{{here}}
>   template <int (*fp)(int)> struct X1 { };
> -  // FIXME: Add reference template parameter tests.
> +  template <int &p> struct X2 { }; // expected-note 4{{here}}
> +  template <const int &p> struct X2k { }; // expected-note {{here}}
> +  template <int (&fp)(int)> struct X3 { }; // expected-note 4{{here}}
>
>   int i = 42;
>   int iarr[10];
>   int f(int i);
> +  const int ki = 9; // expected-note 5{{here}}
> +  __thread int ti = 100; // expected-note 2{{here}}

Fails like this on mac:

******************** TEST 'Clang ::
CXX/temp/temp.arg/temp.arg.nontype/p1.cpp' FAILED ********************
Script:
--
/Volumes/MacintoshHD2/src/llvm-svn/Release+Asserts/bin/clang -cc1
-internal-isystem
/Volumes/MacintoshHD2/src/llvm-svn/Release+Asserts/bin/../lib/clang/3.1/include
-fsyntax-only -verify
/Volumes/MacintoshHD2/src/llvm-svn/tools/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
--
Exit Code: 1
Command Output (stderr):
--
error: 'error' diagnostics expected but not seen:
  Line 51: refers to thread-local object
  Line 67: refers to thread-local object
error: 'error' diagnostics seen but not expected:
  Line 40: thread-local storage is unsupported for the current target
error: 'note' diagnostics expected but not seen:
  Line 40: here
  Line 40: here
5 errors generated.
--


> +  static int f_internal(int); // expected-note 4{{here}}
>   template <typename T> T f_tmpl(T t);
> +
>   void test() {
> -    X0<&i> x0a;
> +    X0<i> x0a; // expected-error {{must have its address taken}}
> +    X0<&i> x0a_addr;
>     X0<iarr> x0b;
> -    X1<&f> x1a;
> -    X1<f> x1b;
> -    X1<f_tmpl> x1c;
> -    X1<f_tmpl<int> > x1d;
> +    X0<&iarr> x0b_addr; // expected-error {{cannot be converted to a value of type 'int *'}}
> +    X0<ki> x0c; // expected-error {{must have its address taken}} expected-warning {{internal linkage is a C++11 extension}}
> +    X0<&ki> x0c_addr; // expected-error {{cannot be converted to a value of type 'int *'}} expected-warning {{internal linkage is a C++11 extension}}
> +    X0<&ti> x0d_addr; // expected-error {{refers to thread-local object}}
> +    X1<f> x1a;
> +    X1<&f> x1a_addr;
> +    X1<f_tmpl> x1b;
> +    X1<&f_tmpl> x1b_addr;
> +    X1<f_tmpl<int> > x1c;
> +    X1<&f_tmpl<int> > x1c_addr;
> +    X1<f_internal> x1d; // expected-warning {{internal linkage is a C++11 extension}}
> +    X1<&f_internal> x1d_addr; // expected-warning {{internal linkage is a C++11 extension}}
> +    X2<i> x2a;
> +    X2<&i> x2a_addr; // expected-error {{address taken}}
> +    X2<iarr> x2b; // expected-error {{cannot bind to template argument of type 'int [10]'}}
> +    X2<&iarr> x2b_addr; // expected-error {{address taken}}
> +    X2<ki> x2c; // expected-error {{ignores qualifiers}} expected-warning {{internal linkage is a C++11 extension}}
> +    X2k<ki> x2kc; // expected-warning {{internal linkage is a C++11 extension}}
> +    X2k<&ki> x2kc_addr; // expected-error {{address taken}} expected-warning {{internal linkage is a C++11 extension}}
> +    X2<ti> x2d_addr; // expected-error {{refers to thread-local object}}
> +    X3<f> x3a;
> +    X3<&f> x3a_addr; // expected-error {{address taken}}
> +    X3<f_tmpl> x3b;
> +    X3<&f_tmpl> x3b_addr; // expected-error {{address taken}}
> +    X3<f_tmpl<int> > x3c;
> +    X3<&f_tmpl<int> > x3c_addr; // expected-error {{address taken}}
> +    X3<f_internal> x3d; // expected-warning {{internal linkage is a C++11 extension}}
> +    X3<&f_internal> x3d_addr; // expected-error {{address taken}} expected-warning {{internal linkage is a C++11 extension}}
> +
> +    int n; // expected-note {{here}}
> +    X0<&n> x0_no_linkage; // expected-error {{non-type template argument refers to object 'n' that does not have linkage}}
> +    struct Local { static int f() {} }; // expected-note {{here}}
> +    X1<&Local::f> x1_no_linkage; // expected-error {{non-type template argument refers to function 'f' that does not have linkage}}
>   }
>  }
>
>
> Modified: cfe/trunk/test/CodeGenCXX/mangle-template.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-template.cpp?rev=154053&r1=154052&r2=154053&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/mangle-template.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/mangle-template.cpp Wed Apr  4 16:11:30 2012
> @@ -153,3 +153,20 @@
>   template void f<char>(A<char,cmp> &);
>   // CHECK: @_ZN6test111fIcEEvRNS_1AIT_L_ZNS_3cmpEccEEE(
>  }
> +
> +namespace test12 {
> +  // Make sure we can mangle non-type template args with internal linkage.
> +  static int f();
> +  const int n = 10;
> +  template<typename T, T v> void test() {}
> +  void use() {
> +    // CHECK: define internal void @_ZN6test124testIFivEXadL_ZNS_L1fEvEEEEvv(
> +    test<int(), &f>();
> +    // CHECK: define internal void @_ZN6test124testIRFivEXadL_ZNS_L1fEvEEEEvv(
> +    test<int(&)(), f>();
> +    // CHECK: define internal void @_ZN6test124testIPKiXadL_ZNS_L1nEEEEEvv(
> +    test<const int*, &n>();
> +    // CHECK: define internal void @_ZN6test124testIRKiXadL_ZNS_L1nEEEEEvv(
> +    test<const int&, n>();
> +  }
> +}
>
> Modified: cfe/trunk/test/SemaCXX/cxx98-compat.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx98-compat.cpp?rev=154053&r1=154052&r2=154053&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/cxx98-compat.cpp (original)
> +++ cfe/trunk/test/SemaCXX/cxx98-compat.cpp Wed Apr  4 16:11:30 2012
> @@ -291,3 +291,11 @@
>   const char *s1 = "foo\u0031"; // expected-warning {{specifying character '1' with a universal character name is incompatible with C++98}}
>   const wchar_t *s2 = L"bar\u0085"; // expected-warning {{universal character name referring to a control character is incompatible with C++98}}
>  }
> +
> +namespace NonTypeTemplateArgs {
> +  template<typename T, T v> struct S {};
> +  const int k = 5; // expected-note {{here}}
> +  static void f() {} // expected-note {{here}}
> +  S<const int&, k> s1; // expected-warning {{non-type template argument referring to object 'k' with internal linkage is incompatible with C++98}}
> +  S<void(&)(), f> s2; // expected-warning {{non-type template argument referring to function 'f' with internal linkage is incompatible with C++98}}
> +}
>
>
> _______________________________________________
> 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