diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-04-04 21:11:30 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-04-04 21:11:30 +0000 |
commit | b4051e7047a0085f0679257386ff183aed3e5162 (patch) | |
tree | 86be0a99d548864e167603673e692a5a38dfa50a /lib/Sema/SemaTemplate.cpp | |
parent | 465a8998bd5e2565ed98e1179876ef9266581f74 (diff) |
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
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 74 |
1 files changed, 40 insertions, 34 deletions
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<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); + + // 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<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; |