Hi Richard, (below)
On Wed, Apr 4, 2012 at 2:11 PM, Richard Smith <[email protected]> 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 > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
