зеркало из https://github.com/microsoft/clang-1.git
Finished semantic analysis of non-type template arguments, to check
for non-external names whose address becomes the template argument. This completes C++ [temp.arg.nontype]p1. Note that our interpretation of C++ [temp.arg.nontype]p1b3 differs from EDG's interpretation (we're stricter, and GCC agrees with us). They're opening a core issue about the matter. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64317 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
5fa77e9662
Коммит
cc45cb3630
|
@ -523,7 +523,7 @@ DIAG(note_template_unnamed_type_here, NOTE,
|
|||
"unnamed type used in template argument was declared here")
|
||||
DIAG(err_template_arg_not_class_template, ERROR,
|
||||
"template argument does not refer to a class template")
|
||||
DIAG(note_template_arg_refers_here, NOTE,
|
||||
DIAG(note_template_arg_refers_here_func, NOTE,
|
||||
"template argument refers to function template %0, here")
|
||||
DIAG(err_template_arg_template_params_mismatch, ERROR,
|
||||
"template template argument has different template parameters than its corresponding template template parameter")
|
||||
|
@ -537,7 +537,26 @@ DIAG(err_template_arg_no_ref_bind, ERROR,
|
|||
"non-type template parameter of reference type %0 cannot bind to template argument of type %1")
|
||||
DIAG(err_template_arg_ref_bind_ignores_quals, ERROR,
|
||||
"reference binding of non-type template parameter of type %0 to template argument of type %1 ignores qualifiers")
|
||||
|
||||
DIAG(err_template_arg_not_object_or_func_form, ERROR,
|
||||
"non-type template argument does not directly refer to an object or function")
|
||||
DIAG(err_template_arg_field, ERROR,
|
||||
"non-type template argument refers to non-static data member %0")
|
||||
DIAG(err_template_arg_method, ERROR,
|
||||
"non-type template argument refers to non-static member function %0")
|
||||
DIAG(err_template_arg_function_not_extern, ERROR,
|
||||
"non-template argument refers to function %0 with internal linkage")
|
||||
DIAG(err_template_arg_object_not_extern, ERROR,
|
||||
"non-template argument refers to object %0 that does not have external linkage")
|
||||
DIAG(note_template_arg_internal_object, NOTE,
|
||||
"non-template argument refers to %select{function|object}0 here")
|
||||
DIAG(note_template_arg_refers_here, NOTE,
|
||||
"non-template argument refers here")
|
||||
DIAG(err_template_arg_not_object_or_func, ERROR,
|
||||
"non-type template argument does not refer to an object or function")
|
||||
DIAG(err_template_arg_not_pointer_to_member_form, ERROR,
|
||||
"non-type template argument is not a pointer to member constant")
|
||||
DIAG(err_template_arg_extra_parens, ERROR,
|
||||
"non-type template argument cannot be surrounded by parentheses")
|
||||
|
||||
DIAG(err_unexpected_typedef, ERROR,
|
||||
"unexpected type name %0: expected expression")
|
||||
|
|
|
@ -1547,6 +1547,8 @@ public:
|
|||
|
||||
bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg,
|
||||
SourceLocation ArgLoc);
|
||||
bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg);
|
||||
bool CheckTemplateArgumentPointerToMember(Expr *Arg);
|
||||
bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Expr *&Arg);
|
||||
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg);
|
||||
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "Sema.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/Parse/DeclSpec.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
|
@ -825,6 +826,158 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
|
|||
return false;
|
||||
}
|
||||
|
||||
/// \brief Checks whether the given template argument is the address
|
||||
/// of an object or function according to C++ [temp.arg.nontype]p1.
|
||||
bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg) {
|
||||
bool Invalid = false;
|
||||
|
||||
// See through any implicit casts we added to fix the type.
|
||||
if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
|
||||
Arg = Cast->getSubExpr();
|
||||
|
||||
// C++ [temp.arg.nontype]p1:
|
||||
//
|
||||
// A template-argument for a non-type, non-template
|
||||
// template-parameter shall be one of: [...]
|
||||
//
|
||||
// -- 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
|
||||
DeclRefExpr *DRE = 0;
|
||||
|
||||
// Ignore (and complain about) any excess parentheses.
|
||||
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
|
||||
if (!Invalid) {
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_extra_parens)
|
||||
<< Arg->getSourceRange();
|
||||
Invalid = true;
|
||||
}
|
||||
|
||||
Arg = Parens->getSubExpr();
|
||||
}
|
||||
|
||||
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
|
||||
if (UnOp->getOpcode() == UnaryOperator::AddrOf)
|
||||
DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr());
|
||||
} else
|
||||
DRE = dyn_cast<DeclRefExpr>(Arg);
|
||||
|
||||
if (!DRE || !isa<ValueDecl>(DRE->getDecl()))
|
||||
return Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_not_object_or_func_form)
|
||||
<< Arg->getSourceRange();
|
||||
|
||||
// Cannot refer to non-static data members
|
||||
if (FieldDecl *Field = dyn_cast<FieldDecl>(DRE->getDecl()))
|
||||
return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field)
|
||||
<< Field << Arg->getSourceRange();
|
||||
|
||||
// Cannot refer to non-static member functions
|
||||
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(DRE->getDecl()))
|
||||
if (!Method->isStatic())
|
||||
return Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_method)
|
||||
<< Method << Arg->getSourceRange();
|
||||
|
||||
// Functions must have external linkage.
|
||||
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) {
|
||||
if (Func->getStorageClass() == FunctionDecl::Static) {
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_function_not_extern)
|
||||
<< Func << Arg->getSourceRange();
|
||||
Diag(Func->getLocation(), diag::note_template_arg_internal_object)
|
||||
<< true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Okay: we've named a function with external linkage.
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
|
||||
if (!Var->hasGlobalStorage()) {
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_object_not_extern)
|
||||
<< Var << Arg->getSourceRange();
|
||||
Diag(Var->getLocation(), diag::note_template_arg_internal_object)
|
||||
<< true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Okay: we've named an object with external linkage
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
// We found something else, but we don't know specifically what it is.
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_not_object_or_func)
|
||||
<< Arg->getSourceRange();
|
||||
Diag(DRE->getDecl()->getLocation(),
|
||||
diag::note_template_arg_refers_here);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Checks whether the given template argument is a pointer to
|
||||
/// member constant according to C++ [temp.arg.nontype]p1.
|
||||
bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg) {
|
||||
bool Invalid = false;
|
||||
|
||||
// See through any implicit casts we added to fix the type.
|
||||
if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
|
||||
Arg = Cast->getSubExpr();
|
||||
|
||||
// C++ [temp.arg.nontype]p1:
|
||||
//
|
||||
// A template-argument for a non-type, non-template
|
||||
// template-parameter shall be one of: [...]
|
||||
//
|
||||
// -- a pointer to member expressed as described in 5.3.1.
|
||||
QualifiedDeclRefExpr *DRE = 0;
|
||||
|
||||
// Ignore (and complain about) any excess parentheses.
|
||||
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
|
||||
if (!Invalid) {
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_extra_parens)
|
||||
<< Arg->getSourceRange();
|
||||
Invalid = true;
|
||||
}
|
||||
|
||||
Arg = Parens->getSubExpr();
|
||||
}
|
||||
|
||||
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg))
|
||||
if (UnOp->getOpcode() == UnaryOperator::AddrOf)
|
||||
DRE = dyn_cast<QualifiedDeclRefExpr>(UnOp->getSubExpr());
|
||||
|
||||
if (!DRE)
|
||||
return Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_not_pointer_to_member_form)
|
||||
<< Arg->getSourceRange();
|
||||
|
||||
if (isa<FieldDecl>(DRE->getDecl()) || isa<CXXMethodDecl>(DRE->getDecl())) {
|
||||
assert((isa<FieldDecl>(DRE->getDecl()) ||
|
||||
!cast<CXXMethodDecl>(DRE->getDecl())->isStatic()) &&
|
||||
"Only non-static member pointers can make it here");
|
||||
|
||||
// Okay: this is the address of a non-static member, and therefore
|
||||
// a member pointer constant.
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
// We found something else, but we don't know specifically what it is.
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_not_pointer_to_member_form)
|
||||
<< Arg->getSourceRange();
|
||||
Diag(DRE->getDecl()->getLocation(),
|
||||
diag::note_template_arg_refers_here);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Check a template argument against its corresponding
|
||||
/// non-type template parameter.
|
||||
///
|
||||
|
@ -921,7 +1074,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
(ParamType->isMemberPointerType() &&
|
||||
ParamType->getAsMemberPointerType()->getPointeeType()
|
||||
->isFunctionType())) {
|
||||
if (Context.hasSameUnqualifiedType(ArgType, ParamType.getNonReferenceType())) {
|
||||
if (Context.hasSameUnqualifiedType(ArgType,
|
||||
ParamType.getNonReferenceType())) {
|
||||
// We don't have to do anything: the types already match.
|
||||
} else if (ArgType->isFunctionType() && ParamType->isPointerType()) {
|
||||
ArgType = Context.getPointerType(ArgType);
|
||||
|
@ -936,7 +1090,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
}
|
||||
}
|
||||
|
||||
if (!Context.hasSameUnqualifiedType(ArgType, ParamType.getNonReferenceType())) {
|
||||
if (!Context.hasSameUnqualifiedType(ArgType,
|
||||
ParamType.getNonReferenceType())) {
|
||||
// We can't perform this conversion.
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_not_convertible)
|
||||
|
@ -944,9 +1099,11 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
Diag(Param->getLocation(), diag::note_template_param_here);
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: Check the restrictions in p1!
|
||||
return false;
|
||||
|
||||
if (ParamType->isMemberPointerType())
|
||||
return CheckTemplateArgumentPointerToMember(Arg);
|
||||
|
||||
return CheckTemplateArgumentAddressOfObjectOrFunction(Arg);
|
||||
}
|
||||
|
||||
if (const PointerType *ParamPtrType = ParamType->getAsPointerType()) {
|
||||
|
@ -975,8 +1132,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME: Check the restrictions in p1!
|
||||
return false;
|
||||
return CheckTemplateArgumentAddressOfObjectOrFunction(Arg);
|
||||
}
|
||||
|
||||
if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) {
|
||||
|
@ -1011,10 +1167,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME: Check the restrictions in p1!
|
||||
// CheckAddressConstantExpression(Lvalue) can be modified to do
|
||||
// this.
|
||||
return false;
|
||||
return CheckTemplateArgumentAddressOfObjectOrFunction(Arg);
|
||||
}
|
||||
|
||||
// -- For a non-type template-parameter of type pointer to data
|
||||
|
@ -1034,9 +1187,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME: Check the restrictions in p1.
|
||||
|
||||
return false;
|
||||
return CheckTemplateArgumentPointerToMember(Arg);
|
||||
}
|
||||
|
||||
/// \brief Check a template argument against its corresponding
|
||||
|
@ -1059,7 +1210,8 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
|
|||
if (!isa<ClassTemplateDecl>(Template)) {
|
||||
assert(isa<FunctionTemplateDecl>(Template) &&
|
||||
"Only function templates are possible here");
|
||||
Diag(Arg->getSourceRange().getBegin(), diag::note_template_arg_refers_here)
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::note_template_arg_refers_here_func)
|
||||
<< Template;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,9 +45,13 @@ A<X(17, 42)> *a11; // expected-error{{non-type template argument of type 'class
|
|||
template<X const *Ptr> struct A2;
|
||||
|
||||
X *X_ptr;
|
||||
X an_X;
|
||||
X array_of_Xs[10];
|
||||
A2<X_ptr> *a12;
|
||||
A2<array_of_Xs> *a13;
|
||||
A2<&an_X> *a13_2;
|
||||
A2<(&an_X)> *a13_2; // expected-error{{non-type template argument cannot be surrounded by parentheses}} \
|
||||
// FIXME: expected-error{{unqualified-id}}
|
||||
|
||||
float f(float);
|
||||
|
||||
|
@ -62,7 +66,6 @@ A3<h> *a14_1;
|
|||
A3<&h> *a14_2;
|
||||
A3<f> *a14_3;
|
||||
A3<&f> *a14_4;
|
||||
A3<((&f))> *a14_5;
|
||||
A3<h2> *a14_6; // expected-error{{non-type template argument of type 'float (*)(float)' cannot be converted to a value of type 'int (*)(int)'}} \
|
||||
// FIXME: expected-error{{expected unqualified-id}}
|
||||
A3<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (*)(int)'}}\
|
||||
|
@ -75,7 +78,7 @@ struct Y { } y;
|
|||
|
||||
volatile X * X_volatile_ptr;
|
||||
template<X const &AnX> struct A4; // expected-note 2{{template parameter is declared here}}
|
||||
A4<*X_ptr> *a15_1; // okay
|
||||
A4<an_X> *a15_1; // okay
|
||||
A4<*X_volatile_ptr> *a15_2; // expected-error{{reference binding of non-type template parameter of type 'class X const &' to template argument of type 'class X volatile' ignores qualifiers}} \
|
||||
// FIXME: expected-error{{expected unqualified-id}}
|
||||
A4<y> *15_3; // expected-error{{non-type template parameter of reference type 'class X const &' cannot bind to template argument of type 'struct Y'}}\
|
||||
|
@ -83,9 +86,7 @@ A4<y> *15_3; // expected-error{{non-type template parameter of reference type '
|
|||
|
||||
template<int (&fr)(int)> struct A5; // expected-note 2{{template parameter is declared here}}
|
||||
A5<h> *a16_1;
|
||||
A5<(h)> *a16_2;
|
||||
A5<f> *a16_3;
|
||||
A5<(f)> *a16_4;
|
||||
A5<h2> *a16_6; // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (&)(int)'}} \
|
||||
// FIXME: expected-error{{expected unqualified-id}}
|
||||
A5<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (&)(int)'}}\
|
||||
|
@ -115,3 +116,5 @@ A7<&Z::int_member> *a18_1;
|
|||
A7c<&Z::int_member> *a18_2;
|
||||
A7<&Z::float_member> *a18_3; // expected-error{{non-type template argument of type 'float struct Z::*' cannot be converted to a value of type 'int struct Z::*'}} \
|
||||
// FIXME: expected-error{{unqualified-id}}
|
||||
A7c<(&Z::int_member)> *a18_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}} \
|
||||
// FIXME: expected-error{{expected unqualified-id}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче