From: Richard Smith Date: Wed, 4 Apr 2012 21:11:30 +0000 (+0000) Subject: Implement C++11 [temp.arg.nontype]'s permission to use the address of an object X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b4051e7047a0085f0679257386ff183aed3e5162;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154053 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 480ba958a1..f5a72ca99c 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2361,11 +2361,18 @@ def err_template_arg_field : Error< "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, 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; +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< diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index ec11f8d224..4f6c879317 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3550,10 +3550,10 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, return true; } - NamedDecl *Entity = 0; + NamedDecl *Entity = DRE->getDecl(); // Cannot refer to non-static data members - if (FieldDecl *Field = dyn_cast(DRE->getDecl())) { + if (FieldDecl *Field = dyn_cast(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 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, } // Cannot refer to non-static member functions - if (CXXMethodDecl *Method = dyn_cast(DRE->getDecl())) + if (CXXMethodDecl *Method = dyn_cast(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(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(Entity); + VarDecl *Var = dyn_cast(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 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, ArgType = Func->getType(); } - } else if (VarDecl *Var = dyn_cast(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 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, 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 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, 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; diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp index 14dace89a1..fc997f8b1f 100644 --- a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp +++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp @@ -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 @@ namespace non_type_tmpl_param { template X5::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 struct X0 { }; + template struct X0 { }; // expected-note 4{{here}} template struct X1 { }; - // FIXME: Add reference template parameter tests. + template struct X2 { }; // expected-note 4{{here}} + template struct X2k { }; // expected-note {{here}} + template 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}} + static int f_internal(int); // expected-note 4{{here}} template T f_tmpl(T t); + void test() { - X0<&i> x0a; + X0 x0a; // expected-error {{must have its address taken}} + X0<&i> x0a_addr; X0 x0b; - X1<&f> x1a; - X1 x1b; - X1 x1c; - X1 > x1d; + X0<&iarr> x0b_addr; // expected-error {{cannot be converted to a value of type 'int *'}} + X0 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 x1a; + X1<&f> x1a_addr; + X1 x1b; + X1<&f_tmpl> x1b_addr; + X1 > x1c; + X1<&f_tmpl > x1c_addr; + X1 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 x2a; + X2<&i> x2a_addr; // expected-error {{address taken}} + X2 x2b; // expected-error {{cannot bind to template argument of type 'int [10]'}} + X2<&iarr> x2b_addr; // expected-error {{address taken}} + X2 x2c; // expected-error {{ignores qualifiers}} expected-warning {{internal linkage is a C++11 extension}} + X2k 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 x2d_addr; // expected-error {{refers to thread-local object}} + X3 x3a; + X3<&f> x3a_addr; // expected-error {{address taken}} + X3 x3b; + X3<&f_tmpl> x3b_addr; // expected-error {{address taken}} + X3 > x3c; + X3<&f_tmpl > x3c_addr; // expected-error {{address taken}} + X3 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}} } } diff --git a/test/CodeGenCXX/mangle-template.cpp b/test/CodeGenCXX/mangle-template.cpp index 1eb6a451c1..05c3a5851e 100644 --- a/test/CodeGenCXX/mangle-template.cpp +++ b/test/CodeGenCXX/mangle-template.cpp @@ -153,3 +153,20 @@ namespace test11 { template void f(A &); // 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 void test() {} + void use() { + // CHECK: define internal void @_ZN6test124testIFivEXadL_ZNS_L1fEvEEEEvv( + test(); + // CHECK: define internal void @_ZN6test124testIRFivEXadL_ZNS_L1fEvEEEEvv( + test(); + // CHECK: define internal void @_ZN6test124testIPKiXadL_ZNS_L1nEEEEEvv( + test(); + // CHECK: define internal void @_ZN6test124testIRKiXadL_ZNS_L1nEEEEEvv( + test(); + } +} diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp index 70cac8d54e..47589135c9 100644 --- a/test/SemaCXX/cxx98-compat.cpp +++ b/test/SemaCXX/cxx98-compat.cpp @@ -291,3 +291,11 @@ namespace LiteralUCNs { 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 struct S {}; + const int k = 5; // expected-note {{here}} + static void f() {} // expected-note {{here}} + S s1; // expected-warning {{non-type template argument referring to object 'k' with internal linkage is incompatible with C++98}} + S s2; // expected-warning {{non-type template argument referring to function 'f' with internal linkage is incompatible with C++98}} +}