forked from OSchip/llvm-project
Rudimentary checking of template arguments against their corresponding
template parameters when performing semantic analysis of a template-id naming a class template specialization. llvm-svn: 64185
This commit is contained in:
parent
3af42a8a14
commit
d32e028f79
|
@ -464,7 +464,7 @@ DIAG(err_ovl_surrogate_cand, NOTE,
|
|||
DIAG(err_member_call_without_object, ERROR,
|
||||
"call to non-static member function without an object argument")
|
||||
|
||||
/// C++ Templates Semantic Analysis
|
||||
// C++ Template Declarations
|
||||
DIAG(err_template_param_shadow, ERROR,
|
||||
"declaration of %0 shadows template parameter")
|
||||
DIAG(note_template_param_here, NOTE,
|
||||
|
@ -488,6 +488,26 @@ DIAG(err_template_nontype_parm_different_type, ERROR,
|
|||
DIAG(note_template_nontype_parm_prev_declaration, NOTE,
|
||||
"previous non-type template parameter with type %0 is here")
|
||||
|
||||
// C++ Template Argument Lists
|
||||
DIAG(err_template_arg_list_different_arity, ERROR,
|
||||
"%select{too few|too many}0 template arguments for %select{class template|function template|template template parameter|template}1 %2")
|
||||
DIAG(note_template_parameter_here, ERROR,
|
||||
"template parameter is declared here")
|
||||
DIAG(err_template_arg_must_be_type, ERROR,
|
||||
"template argument for template type parameter must be a type")
|
||||
DIAG(err_template_arg_must_be_expr, ERROR,
|
||||
"template argument for non-type template parameter must be an expression")
|
||||
DIAG(err_template_arg_nontype_ambig, ERROR,
|
||||
"template argument for non-type template parameter is treated as type %0")
|
||||
DIAG(err_template_arg_must_be_template, ERROR,
|
||||
"template argument for template template parameter must be a template")
|
||||
DIAG(err_template_arg_local_type, ERROR,
|
||||
"template argument uses local type %0")
|
||||
DIAG(err_template_arg_unnamed_type, ERROR,
|
||||
"template argument uses unnamed type")
|
||||
DIAG(note_template_unnamed_type_here, NOTE,
|
||||
"unnamed type used in template argument was declared here")
|
||||
|
||||
DIAG(err_unexpected_typedef, ERROR,
|
||||
"unexpected type name %0: expected expression")
|
||||
DIAG(err_unexpected_namespace, ERROR,
|
||||
|
|
|
@ -1134,8 +1134,10 @@ public:
|
|||
/// new class template specialization.
|
||||
virtual TypeTy *
|
||||
ActOnClassTemplateSpecialization(DeclTy *Template,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr TemplateArgs,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
SourceLocation RAngleLoc,
|
||||
const CXXScopeSpec *SS = 0) {
|
||||
return 0;
|
||||
|
|
|
@ -567,7 +567,7 @@ namespace clang
|
|||
#endif
|
||||
Args(Other.Args), ArgIsType(Other.ArgIsType), Count(Other.Count) {
|
||||
#if !defined(DISABLE_SMART_POINTERS)
|
||||
Other.destroy();
|
||||
Other.Count = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -1007,10 +1007,12 @@ private:
|
|||
// C++ 14.3: Template arguments [temp.arg]
|
||||
typedef llvm::SmallVector<void *, 16> TemplateArgList;
|
||||
typedef llvm::SmallVector<bool, 16> TemplateArgIsTypeList;
|
||||
typedef llvm::SmallVector<SourceLocation, 16> TemplateArgLocationList;
|
||||
void AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
|
||||
const CXXScopeSpec *SS = 0);
|
||||
bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
|
||||
TemplateArgIsTypeList &TemplateArgIsType);
|
||||
TemplateArgIsTypeList &TemplateArgIsType,
|
||||
TemplateArgLocationList &TemplateArgLocations);
|
||||
void *ParseTemplateArgument(bool &ArgIsType);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
|
@ -943,7 +943,7 @@ bool ClassTemplateSpecializationType::isArgType(unsigned Arg) const {
|
|||
const unsigned BitsPerWord = sizeof(uintptr_t) * CHAR_BIT;
|
||||
const uintptr_t *Data = reinterpret_cast<const uintptr_t *>(this + 1);
|
||||
Data += Arg / BitsPerWord;
|
||||
return (*Data >> (Arg % BitsPerWord)) & 0x01;
|
||||
return (*Data >> ((NumArgs - Arg) % BitsPerWord - 1)) & 0x01;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -370,10 +370,13 @@ void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
|
|||
// Parse the optional template-argument-list.
|
||||
TemplateArgList TemplateArgs;
|
||||
TemplateArgIsTypeList TemplateArgIsType;
|
||||
TemplateArgLocationList TemplateArgLocations;
|
||||
|
||||
{
|
||||
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
|
||||
if (Tok.isNot(tok::greater) &&
|
||||
ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType)) {
|
||||
ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType,
|
||||
TemplateArgLocations)) {
|
||||
// Try to find the closing '>'.
|
||||
SkipUntil(tok::greater, true, true);
|
||||
|
||||
|
@ -417,9 +420,14 @@ void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
|
|||
&TemplateArgIsType[0],
|
||||
TemplateArgs.size());
|
||||
TypeTy *Ty
|
||||
= Actions.ActOnClassTemplateSpecialization(Template, LAngleLoc,
|
||||
TemplateArgsPtr,
|
||||
= Actions.ActOnClassTemplateSpecialization(Template, TemplateNameLoc,
|
||||
LAngleLoc, TemplateArgsPtr,
|
||||
&TemplateArgLocations[0],
|
||||
RAngleLoc, SS);
|
||||
|
||||
if (!Ty) // Something went wrong; don't annotate
|
||||
return;
|
||||
|
||||
Tok.setKind(tok::annot_typename);
|
||||
Tok.setAnnotationValue(Ty);
|
||||
}
|
||||
|
@ -453,8 +461,8 @@ void *Parser::ParseTemplateArgument(bool &ArgIsType) {
|
|||
return ParseTypeName();
|
||||
}
|
||||
|
||||
OwningExprResult ExprArg = ParseExpression();
|
||||
if (ExprArg.isInvalid())
|
||||
OwningExprResult ExprArg = ParseAssignmentExpression();
|
||||
if (ExprArg.isInvalid() || !ExprArg.get())
|
||||
return 0;
|
||||
|
||||
ArgIsType = false;
|
||||
|
@ -469,13 +477,16 @@ void *Parser::ParseTemplateArgument(bool &ArgIsType) {
|
|||
/// template-argument-list ',' template-argument
|
||||
bool
|
||||
Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
|
||||
TemplateArgIsTypeList &TemplateArgIsType) {
|
||||
TemplateArgIsTypeList &TemplateArgIsType,
|
||||
TemplateArgLocationList &TemplateArgLocations) {
|
||||
while (true) {
|
||||
bool IsType = false;
|
||||
SourceLocation Loc = Tok.getLocation();
|
||||
void *Arg = ParseTemplateArgument(IsType);
|
||||
if (Arg) {
|
||||
TemplateArgs.push_back(Arg);
|
||||
TemplateArgIsType.push_back(IsType);
|
||||
TemplateArgLocations.push_back(Loc);
|
||||
} else {
|
||||
SkipUntil(tok::comma, tok::greater, true, true);
|
||||
return true;
|
||||
|
|
|
@ -62,6 +62,7 @@ namespace clang {
|
|||
class TypedefDecl;
|
||||
class TemplateDecl;
|
||||
class TemplateParameterList;
|
||||
class TemplateTemplateParmDecl;
|
||||
class ObjCInterfaceDecl;
|
||||
class ObjCCompatibleAliasDecl;
|
||||
class ObjCProtocolDecl;
|
||||
|
@ -1516,11 +1517,24 @@ public:
|
|||
|
||||
virtual TypeTy *
|
||||
ActOnClassTemplateSpecialization(DeclTy *Template,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr TemplateArgs,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
SourceLocation RAngleLoc,
|
||||
const CXXScopeSpec *SS = 0);
|
||||
|
||||
bool CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr& TemplateArgs,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
SourceLocation RAngleLoc);
|
||||
|
||||
bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg,
|
||||
SourceLocation ArgLoc);
|
||||
bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Expr *Arg);
|
||||
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg);
|
||||
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
|
||||
TemplateParameterList *Old,
|
||||
bool Complain,
|
||||
|
|
|
@ -746,7 +746,9 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
|||
if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D))
|
||||
return Owned(BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc,
|
||||
false, false, SS));
|
||||
|
||||
else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
|
||||
return Owned(BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
|
||||
false, false, SS));
|
||||
ValueDecl *VD = cast<ValueDecl>(D);
|
||||
|
||||
// check if referencing an identifier with __attribute__((deprecated)).
|
||||
|
|
|
@ -356,14 +356,24 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
|
|||
return NewTemplate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Action::TypeTy *
|
||||
Sema::ActOnClassTemplateSpecialization(DeclTy *TemplateD,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr TemplateArgs,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
SourceLocation RAngleLoc,
|
||||
const CXXScopeSpec *SS) {
|
||||
TemplateDecl *Template = cast<TemplateDecl>(static_cast<Decl *>(TemplateD));
|
||||
|
||||
// Check that the template argument list is well-formed for this
|
||||
// template.
|
||||
if (!CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc,
|
||||
TemplateArgs, TemplateArgLocs, RAngleLoc))
|
||||
return 0;
|
||||
|
||||
// Yes, all class template specializations are just silly sugar for
|
||||
// 'int'. Gotta problem wit dat?
|
||||
QualType Result
|
||||
|
@ -376,6 +386,178 @@ Sema::ActOnClassTemplateSpecialization(DeclTy *TemplateD,
|
|||
return Result.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
/// \brief Check that the given template argument list is well-formed
|
||||
/// for specializing the given template.
|
||||
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr& Args,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
SourceLocation RAngleLoc) {
|
||||
TemplateParameterList *Params = Template->getTemplateParameters();
|
||||
unsigned NumParams = Params->size();
|
||||
unsigned NumArgs = Args.size();
|
||||
bool Invalid = false;
|
||||
|
||||
if (NumArgs > NumParams ||
|
||||
NumArgs < NumParams /*FIXME: default arguments! */) {
|
||||
// FIXME: point at either the first arg beyond what we can handle,
|
||||
// or the '>', depending on whether we have too many or too few
|
||||
// arguments.
|
||||
SourceRange Range;
|
||||
if (NumArgs > NumParams)
|
||||
Range = SourceRange(TemplateArgLocs[NumParams], RAngleLoc);
|
||||
Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
|
||||
<< (NumArgs > NumParams)
|
||||
<< (isa<ClassTemplateDecl>(Template)? 0 :
|
||||
isa<FunctionTemplateDecl>(Template)? 1 :
|
||||
isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
|
||||
<< Template << Range;
|
||||
|
||||
Invalid = true;
|
||||
}
|
||||
|
||||
// C++ [temp.arg]p1:
|
||||
// [...] The type and form of each template-argument specified in
|
||||
// a template-id shall match the type and form specified for the
|
||||
// corresponding parameter declared by the template in its
|
||||
// template-parameter-list.
|
||||
unsigned ArgIdx = 0;
|
||||
for (TemplateParameterList::iterator Param = Params->begin(),
|
||||
ParamEnd = Params->end();
|
||||
Param != ParamEnd; ++Param, ++ArgIdx) {
|
||||
// Decode the template argument
|
||||
QualType ArgType;
|
||||
Expr *ArgExpr = 0;
|
||||
SourceLocation ArgLoc;
|
||||
if (ArgIdx >= NumArgs) {
|
||||
// FIXME: Get the default argument here, which might
|
||||
// (eventually) require instantiation.
|
||||
break;
|
||||
} else
|
||||
ArgLoc = TemplateArgLocs[ArgIdx];
|
||||
|
||||
if (Args.getArgIsType()[ArgIdx])
|
||||
ArgType = QualType::getFromOpaquePtr(Args.getArgs()[ArgIdx]);
|
||||
else
|
||||
ArgExpr = reinterpret_cast<Expr *>(Args.getArgs()[ArgIdx]);
|
||||
|
||||
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
|
||||
// Check template type parameters.
|
||||
if (!ArgType.isNull()) {
|
||||
if (!CheckTemplateArgument(TTP, ArgType, ArgLoc))
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// C++ [temp.arg.type]p1:
|
||||
// A template-argument for a template-parameter which is a
|
||||
// type shall be a type-id.
|
||||
|
||||
// We have a template type parameter but the template argument
|
||||
// is an expression.
|
||||
Diag(ArgExpr->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_must_be_type);
|
||||
Diag((*Param)->getLocation(), diag::note_template_parameter_here);
|
||||
Invalid = true;
|
||||
} else if (NonTypeTemplateParmDecl *NTTP
|
||||
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
|
||||
// Check non-type template parameters.
|
||||
if (ArgExpr) {
|
||||
if (!CheckTemplateArgument(NTTP, ArgExpr))
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have a non-type template parameter but the template
|
||||
// argument is a type.
|
||||
|
||||
// C++ [temp.arg]p2:
|
||||
// In a template-argument, an ambiguity between a type-id and
|
||||
// an expression is resolved to a type-id, regardless of the
|
||||
// form of the corresponding template-parameter.
|
||||
//
|
||||
// We warn specifically about this case, since it can be rather
|
||||
// confusing for users.
|
||||
if (ArgType->isFunctionType())
|
||||
Diag(ArgLoc, diag::err_template_arg_nontype_ambig)
|
||||
<< ArgType;
|
||||
else
|
||||
Diag(ArgLoc, diag::err_template_arg_must_be_expr);
|
||||
Diag((*Param)->getLocation(), diag::note_template_parameter_here);
|
||||
Invalid = true;
|
||||
} else {
|
||||
// Check template template parameters.
|
||||
TemplateTemplateParmDecl *TempParm
|
||||
= cast<TemplateTemplateParmDecl>(*Param);
|
||||
|
||||
if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
|
||||
isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) {
|
||||
if (!CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr)))
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have a template template parameter but the template
|
||||
// argument does not refer to a template.
|
||||
Diag(ArgLoc, diag::err_template_arg_must_be_template);
|
||||
Invalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
/// \brief Check a template argument against its corresponding
|
||||
/// template type parameter.
|
||||
///
|
||||
/// This routine implements the semantics of C++ [temp.arg.type]. It
|
||||
/// returns true if an error occurred, and false otherwise.
|
||||
bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
|
||||
QualType Arg, SourceLocation ArgLoc) {
|
||||
// C++ [temp.arg.type]p2:
|
||||
// A local type, a type with no linkage, an unnamed type or a type
|
||||
// compounded from any of these types shall not be used as a
|
||||
// template-argument for a template type-parameter.
|
||||
//
|
||||
// FIXME: Perform the recursive and no-linkage type checks.
|
||||
const TagType *Tag = 0;
|
||||
if (const EnumType *EnumT = Arg->getAsEnumType())
|
||||
Tag = EnumT;
|
||||
else if (const RecordType *RecordT = Arg->getAsRecordType())
|
||||
Tag = RecordT;
|
||||
if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod())
|
||||
return Diag(ArgLoc, diag::err_template_arg_local_type)
|
||||
<< QualType(Tag, 0);
|
||||
else if (Tag && !Tag->getDecl()->getDeclName()) {
|
||||
Diag(ArgLoc, diag::err_template_arg_unnamed_type);
|
||||
Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Check a template argument against its corresponding
|
||||
/// non-type template parameter.
|
||||
///
|
||||
/// This routine implements the semantics of C++ [temp.arg.nontype].
|
||||
/// It returns true if an error occurred, and false otherwise.
|
||||
bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
Expr *Arg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Check a template argument against its corresponding
|
||||
/// template template parameter.
|
||||
///
|
||||
/// This routine implements the semantics of C++ [temp.arg.template].
|
||||
/// It returns true if an error occurred, and false otherwise.
|
||||
bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
|
||||
DeclRefExpr *Arg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Determine whether the given template parameter lists are
|
||||
/// equivalent.
|
||||
///
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
// RUN: clang -fsyntax-only -verify %s
|
||||
template<typename T,
|
||||
int I,
|
||||
template<typename> class TT>
|
||||
class A;
|
||||
|
||||
template<typename> class X;
|
||||
|
||||
A<int, 0, X> * a1;
|
||||
|
||||
A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}}
|
||||
|
||||
A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}}
|
|
@ -0,0 +1,27 @@
|
|||
// RUN: clang -fsyntax-only -verify %s
|
||||
template<typename T> class A; // expected-error 2 {{template parameter is declared here}}
|
||||
|
||||
// [temp.arg.type]p1
|
||||
A<0> *a1; // expected-error{{template argument for template type parameter must be a type}}
|
||||
|
||||
A<A> *a2; // expected-error{{template argument for template type parameter must be a type}}
|
||||
|
||||
A<int> *a3;
|
||||
// FIXME: The two below are well-formed, but we're not parsing them as type-ids.
|
||||
// A<int()> *a4;
|
||||
// A<int(float)> *a5;
|
||||
A<A<int> > *a6;
|
||||
|
||||
// [temp.arg.type]p2
|
||||
void f() {
|
||||
class X { };
|
||||
A<X> * a = 0; // expected-error{{template argument uses local type 'class X'}}\
|
||||
// FIXME: expected-error{{expected expression}}
|
||||
}
|
||||
|
||||
struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}}
|
||||
A<__typeof__(Unnamed)> *a7; // expected-error{{template argument uses unnamed type}} \
|
||||
// FIXME: expected-error{{expected unqualified-id}}
|
||||
|
||||
// FIXME: [temp.arg.type]p3. The check doesn't really belong here (it
|
||||
// belongs somewhere in the template instantiation section).
|
Loading…
Reference in New Issue