зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
465a8998bd
Коммит
b4051e7047
|
@ -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<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<
|
||||
|
|
|
@ -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<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 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
|
|||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// Okay: we've named a function with external linkage.
|
||||
Entity = Func;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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<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 @@ 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;
|
||||
|
|
|
@ -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 <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}}
|
||||
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}}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -153,3 +153,20 @@ namespace test11 {
|
|||
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>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<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}}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче