Parsing and AST representation for dependent template names that occur
within nested-name-specifiers, e.g., for the "apply" in typename MetaFun::template apply<T1, T2>::type At present, we can't instantiate these nested-name-specifiers, so our testing is sketchy. llvm-svn: 68081
This commit is contained in:
parent
b874bd9f41
commit
b67535d1b6
|
@ -699,6 +699,9 @@ def err_typename_nested_not_type : Error<
|
|||
def note_typename_refers_here : Note<
|
||||
"referenced member %0 is declared here">;
|
||||
|
||||
def err_template_kw_refers_to_non_template : Error<
|
||||
"%0 following the 'template' keyword does not refer to a template">;
|
||||
|
||||
def err_unexpected_typedef : Error<
|
||||
"unexpected type name %0: expected expression">;
|
||||
def err_unexpected_namespace : Error<
|
||||
|
|
|
@ -22,12 +22,14 @@ enum TemplateNameKind {
|
|||
/// The name refers to a function template or a set of overloaded
|
||||
/// functions that includes at least one function template.
|
||||
TNK_Function_template,
|
||||
/// The name refers to a class template.
|
||||
TNK_Class_template,
|
||||
/// The name referes to a template template parameter.
|
||||
TNK_Template_template_parm,
|
||||
/// The name is dependent and is known to be a template name based
|
||||
/// on syntax, e.g., "Alloc::template rebind<Other>".
|
||||
/// The name refers to a template whose specialization produces a
|
||||
/// type. The template itself could be a class template, template
|
||||
/// template parameter, or C++0x template alias.
|
||||
TNK_Type_template,
|
||||
/// The name refers to a dependent template name. Whether the
|
||||
/// template name is assumed to refer to a type template or a
|
||||
/// function template depends on the context in which the template
|
||||
/// name occurs.
|
||||
TNK_Dependent_template_name
|
||||
};
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ public:
|
|||
/// returned, and \p TemplateDecl receives the declaration. An
|
||||
/// optional CXXScope can be passed to indicate the C++ scope in
|
||||
/// which the identifier will be found.
|
||||
virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S,
|
||||
virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
|
||||
TemplateTy &Template,
|
||||
const CXXScopeSpec *SS = 0) = 0;
|
||||
|
||||
|
@ -1229,6 +1229,20 @@ public:
|
|||
return TypeResult();
|
||||
};
|
||||
|
||||
/// \brief Form a dependent template name.
|
||||
///
|
||||
/// This action forms a dependent template name given the template
|
||||
/// name and its (presumably dependent) scope specifier. For
|
||||
/// example, given "MetaFun::template apply", the scope specifier \p
|
||||
/// SS will be "MetaFun::", \p TemplateKWLoc contains the location
|
||||
/// of the "template" keyword, and "apply" is the \p Name.
|
||||
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
|
||||
const IdentifierInfo &Name,
|
||||
SourceLocation NameLoc,
|
||||
const CXXScopeSpec &SS) {
|
||||
return TemplateTy();
|
||||
}
|
||||
|
||||
/// \brief Process the declaration or definition of an explicit
|
||||
/// class template specialization or a class template partial
|
||||
/// specialization.
|
||||
|
@ -1568,7 +1582,7 @@ public:
|
|||
virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S,
|
||||
const CXXScopeSpec *SS);
|
||||
|
||||
virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S,
|
||||
virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
|
||||
TemplateTy &Template,
|
||||
const CXXScopeSpec *SS = 0);
|
||||
|
||||
|
|
|
@ -1373,8 +1373,6 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
|
|||
const TemplateArgument *Args,
|
||||
unsigned NumArgs,
|
||||
QualType Canon) {
|
||||
// FIXME: If Template is dependent, canonicalize it!
|
||||
|
||||
if (!Canon.isNull())
|
||||
Canon = getCanonicalType(Canon);
|
||||
|
||||
|
|
|
@ -94,8 +94,12 @@ QualType Type::getDesugaredType() const {
|
|||
if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this))
|
||||
return TOT->getUnderlyingType().getDesugaredType();
|
||||
if (const TemplateSpecializationType *Spec
|
||||
= dyn_cast<TemplateSpecializationType>(this))
|
||||
return Spec->getCanonicalTypeInternal().getDesugaredType();
|
||||
= dyn_cast<TemplateSpecializationType>(this)) {
|
||||
QualType Canon = Spec->getCanonicalTypeInternal();
|
||||
if (Canon->getAsTemplateSpecializationType())
|
||||
return QualType(this, 0);
|
||||
return Canon->getDesugaredType();
|
||||
}
|
||||
if (const QualifiedNameType *QualName = dyn_cast<QualifiedNameType>(this))
|
||||
return QualName->getNamedType().getDesugaredType();
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
|
|||
}
|
||||
|
||||
TemplateNameKind
|
||||
MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S,
|
||||
MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S,
|
||||
TemplateTy &TemplateDecl,
|
||||
const CXXScopeSpec *SS) {
|
||||
return TNK_Non_template;
|
||||
|
|
|
@ -513,7 +513,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
Token Next = NextToken();
|
||||
if (Next.is(tok::annot_template_id) &&
|
||||
static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
|
||||
->Kind == TNK_Class_template) {
|
||||
->Kind == TNK_Type_template) {
|
||||
// We have a qualified template-id, e.g., N::A<int>
|
||||
CXXScopeSpec SS;
|
||||
ParseOptionalCXXScopeSpecifier(SS);
|
||||
|
@ -640,7 +640,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
case tok::annot_template_id: {
|
||||
TemplateIdAnnotation *TemplateId
|
||||
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
||||
if (TemplateId->Kind != TNK_Class_template) {
|
||||
if (TemplateId->Kind != TNK_Type_template) {
|
||||
// This template-id does not refer to a type name, so we're
|
||||
// done with the type-specifiers.
|
||||
goto DoneWithDeclSpec;
|
||||
|
|
|
@ -307,7 +307,7 @@ Parser::TypeTy *Parser::ParseClassName(SourceLocation &EndLocation,
|
|||
if (Tok.is(tok::annot_template_id)) {
|
||||
TemplateIdAnnotation *TemplateId
|
||||
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
||||
if (TemplateId->Kind == TNK_Class_template) {
|
||||
if (TemplateId->Kind == TNK_Type_template) {
|
||||
if (AnnotateTemplateIdTokenAsType(SS))
|
||||
return 0;
|
||||
|
||||
|
@ -419,7 +419,7 @@ void Parser::ParseClassSpecifier(DeclSpec &DS,
|
|||
TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
||||
NameLoc = ConsumeToken();
|
||||
|
||||
if (TemplateId->Kind != TNK_Class_template) {
|
||||
if (TemplateId->Kind != TNK_Type_template) {
|
||||
// The template-name in the simple-template-id refers to
|
||||
// something other than a class template. Give an appropriate
|
||||
// error message and skip to the ';'.
|
||||
|
|
|
@ -92,9 +92,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
|
|||
Tok.is(tok::kw_template)) {
|
||||
// Parse the optional 'template' keyword, then make sure we have
|
||||
// 'identifier <' after it.
|
||||
SourceLocation TemplateKWLoc;
|
||||
if (Tok.is(tok::kw_template)) {
|
||||
TemplateKWLoc = ConsumeToken();
|
||||
SourceLocation TemplateKWLoc = ConsumeToken();
|
||||
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
Diag(Tok.getLocation(),
|
||||
|
@ -110,20 +109,20 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
|
|||
<< SourceRange(TemplateKWLoc, Tok.getLocation());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// FIXME: If the nested-name-specifier thus far is dependent,
|
||||
// we need to break out of here, because this '<' is taken as
|
||||
// an operator and not as part of a simple-template-id.
|
||||
|
||||
TemplateTy Template
|
||||
= Actions.ActOnDependentTemplateName(TemplateKWLoc,
|
||||
*Tok.getIdentifierInfo(),
|
||||
Tok.getLocation(),
|
||||
SS);
|
||||
AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
|
||||
&SS, TemplateKWLoc, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
TemplateTy Template;
|
||||
TemplateNameKind TNK = TNK_Non_template;
|
||||
// FIXME: If the nested-name-specifier thus far is dependent,
|
||||
// set TNK = TNK_Dependent_template_name and skip the
|
||||
// "isTemplateName" check.
|
||||
TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
|
||||
CurScope, Template, &SS);
|
||||
TemplateNameKind TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
|
||||
CurScope, Template, &SS);
|
||||
if (TNK) {
|
||||
// We have found a template name, so annotate this this token
|
||||
// with a template-id annotation. We do not permit the
|
||||
|
@ -131,7 +130,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
|
|||
// because some clients (e.g., the parsing of class template
|
||||
// specializations) still want to see the original template-id
|
||||
// token.
|
||||
AnnotateTemplateIdToken(Template, TNK, &SS, TemplateKWLoc, false);
|
||||
AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(), false);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -142,12 +141,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
|
|||
// simple-template-id '::'
|
||||
//
|
||||
// So we need to check whether the simple-template-id is of the
|
||||
// right kind (it should name a type), and then convert it into
|
||||
// a type within the nested-name-specifier.
|
||||
// right kind (it should name a type or be dependent), and then
|
||||
// convert it into a type within the nested-name-specifier.
|
||||
TemplateIdAnnotation *TemplateId
|
||||
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
||||
|
||||
if (TemplateId->Kind == TNK_Class_template) {
|
||||
if (TemplateId->Kind == TNK_Type_template ||
|
||||
TemplateId->Kind == TNK_Dependent_template_name) {
|
||||
if (AnnotateTemplateIdTokenAsType(&SS))
|
||||
SS.clear();
|
||||
|
||||
|
@ -172,7 +172,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
|
|||
SS.setEndLoc(CCLoc);
|
||||
continue;
|
||||
} else
|
||||
assert(false && "FIXME: Only class template names supported here");
|
||||
assert(false && "FIXME: Only type template names supported here");
|
||||
}
|
||||
|
||||
// We don't have any tokens that form the beginning of a
|
||||
|
|
|
@ -531,8 +531,7 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
|
|||
return;
|
||||
|
||||
// Build the annotation token.
|
||||
// FIXME: Not just for class templates!
|
||||
if (TNK == TNK_Class_template && AllowTypeAnnotation) {
|
||||
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
|
||||
Action::TypeResult Type
|
||||
= Actions.ActOnTemplateIdType(Template, TemplateNameLoc,
|
||||
LAngleLoc, TemplateArgsPtr,
|
||||
|
@ -550,8 +549,8 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
|
|||
else
|
||||
Tok.setLocation(TemplateNameLoc);
|
||||
} else {
|
||||
// This is a function template. We'll be building a template-id
|
||||
// annotation token.
|
||||
// Build a template-id annotation token that can be processed
|
||||
// later.
|
||||
Tok.setKind(tok::annot_template_id);
|
||||
TemplateIdAnnotation *TemplateId
|
||||
= TemplateIdAnnotation::Allocate(TemplateArgs.size());
|
||||
|
@ -595,8 +594,9 @@ bool Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
|
|||
|
||||
TemplateIdAnnotation *TemplateId
|
||||
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
||||
assert(TemplateId->Kind == TNK_Class_template &&
|
||||
"Only works for class templates");
|
||||
assert((TemplateId->Kind == TNK_Type_template ||
|
||||
TemplateId->Kind == TNK_Dependent_template_name) &&
|
||||
"Only works for type and dependent templates");
|
||||
|
||||
ASTTemplateArgsPtr TemplateArgsPtr(Actions,
|
||||
TemplateId->getTemplateArgs(),
|
||||
|
|
|
@ -901,7 +901,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
|
|||
if (Tok.is(tok::annot_template_id)) {
|
||||
TemplateIdAnnotation *TemplateId
|
||||
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
||||
if (TemplateId->Kind == TNK_Class_template) {
|
||||
if (TemplateId->Kind == TNK_Type_template) {
|
||||
// A template-id that refers to a type was parsed into a
|
||||
// template-id annotation in a context where we weren't allowed
|
||||
// to produce a type annotation token. Update the template-id
|
||||
|
|
|
@ -1690,7 +1690,7 @@ public:
|
|||
//===--------------------------------------------------------------------===//
|
||||
// C++ Templates [C++ 14]
|
||||
//
|
||||
virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S,
|
||||
virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
|
||||
TemplateTy &Template,
|
||||
const CXXScopeSpec *SS = 0);
|
||||
bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
|
||||
|
@ -1756,6 +1756,11 @@ public:
|
|||
SourceLocation *TemplateArgLocs,
|
||||
SourceLocation RAngleLoc);
|
||||
|
||||
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
|
||||
const IdentifierInfo &Name,
|
||||
SourceLocation NameLoc,
|
||||
const CXXScopeSpec &SS);
|
||||
|
||||
bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
|
||||
ClassTemplateSpecializationDecl *PrevDecl,
|
||||
SourceLocation TemplateNameLoc,
|
||||
|
|
|
@ -26,7 +26,7 @@ using namespace clang;
|
|||
/// declaration if II names a template. An optional CXXScope can be
|
||||
/// passed to indicate the C++ scope in which the identifier will be
|
||||
/// found.
|
||||
TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S,
|
||||
TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S,
|
||||
TemplateTy &TemplateResult,
|
||||
const CXXScopeSpec *SS) {
|
||||
NamedDecl *IIDecl = LookupParsedName(S, SS, &II, LookupOrdinaryName);
|
||||
|
@ -38,10 +38,9 @@ TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S,
|
|||
if ((Template = dyn_cast<TemplateDecl>(IIDecl))) {
|
||||
if (isa<FunctionTemplateDecl>(IIDecl))
|
||||
TNK = TNK_Function_template;
|
||||
else if (isa<ClassTemplateDecl>(IIDecl))
|
||||
TNK = TNK_Class_template;
|
||||
else if (isa<TemplateTemplateParmDecl>(IIDecl))
|
||||
TNK = TNK_Template_template_parm;
|
||||
else if (isa<ClassTemplateDecl>(IIDecl) ||
|
||||
isa<TemplateTemplateParmDecl>(IIDecl))
|
||||
TNK = TNK_Type_template;
|
||||
else
|
||||
assert(false && "Unknown template declaration kind");
|
||||
} else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(IIDecl)) {
|
||||
|
@ -59,11 +58,11 @@ TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S,
|
|||
if (Record->isInjectedClassName()) {
|
||||
Record = cast<CXXRecordDecl>(Context.getCanonicalDecl(Record));
|
||||
if ((Template = Record->getDescribedClassTemplate()))
|
||||
TNK = TNK_Class_template;
|
||||
TNK = TNK_Type_template;
|
||||
else if (ClassTemplateSpecializationDecl *Spec
|
||||
= dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
|
||||
Template = Spec->getSpecializedTemplate();
|
||||
TNK = TNK_Class_template;
|
||||
TNK = TNK_Type_template;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -716,6 +715,56 @@ translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief Build a canonical version of a template argument list.
|
||||
///
|
||||
/// This function builds a canonical version of the given template
|
||||
/// argument list, where each of the template arguments has been
|
||||
/// converted into its canonical form. This routine is typically used
|
||||
/// to canonicalize a template argument list when the template name
|
||||
/// itself is dependent. When the template name refers to an actual
|
||||
/// template declaration, Sema::CheckTemplateArgumentList should be
|
||||
/// used to check and canonicalize the template arguments.
|
||||
///
|
||||
/// \param TemplateArgs The incoming template arguments.
|
||||
///
|
||||
/// \param NumTemplateArgs The number of template arguments in \p
|
||||
/// TemplateArgs.
|
||||
///
|
||||
/// \param Canonical A vector to be filled with the canonical versions
|
||||
/// of the template arguments.
|
||||
///
|
||||
/// \param Context The ASTContext in which the template arguments live.
|
||||
static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs,
|
||||
llvm::SmallVectorImpl<TemplateArgument> &Canonical,
|
||||
ASTContext &Context) {
|
||||
Canonical.reserve(NumTemplateArgs);
|
||||
for (unsigned Idx = 0; Idx < NumTemplateArgs; ++Idx) {
|
||||
switch (TemplateArgs[Idx].getKind()) {
|
||||
case TemplateArgument::Expression:
|
||||
// FIXME: Build canonical expression (!)
|
||||
Canonical.push_back(TemplateArgs[Idx]);
|
||||
break;
|
||||
|
||||
case TemplateArgument::Declaration:
|
||||
Canonical.push_back(TemplateArgument(SourceLocation(),
|
||||
TemplateArgs[Idx].getAsDecl()));
|
||||
break;
|
||||
|
||||
case TemplateArgument::Integral:
|
||||
Canonical.push_back(TemplateArgument(SourceLocation(),
|
||||
*TemplateArgs[Idx].getAsIntegral(),
|
||||
TemplateArgs[Idx].getIntegralType()));
|
||||
|
||||
case TemplateArgument::Type: {
|
||||
QualType CanonType
|
||||
= Context.getCanonicalType(TemplateArgs[Idx].getAsType());
|
||||
Canonical.push_back(TemplateArgument(SourceLocation(), CanonType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QualType Sema::CheckTemplateIdType(TemplateName Name,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
|
@ -723,7 +772,25 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
|
|||
unsigned NumTemplateArgs,
|
||||
SourceLocation RAngleLoc) {
|
||||
TemplateDecl *Template = Name.getAsTemplateDecl();
|
||||
assert(Template && "Cannot handle dependent template-names yet");
|
||||
if (!Template) {
|
||||
// The template name does not resolve to a template, so we just
|
||||
// build a dependent template-id type.
|
||||
|
||||
// Canonicalize the template arguments to build the canonical
|
||||
// template-id type.
|
||||
llvm::SmallVector<TemplateArgument, 16> CanonicalTemplateArgs;
|
||||
CanonicalizeTemplateArguments(TemplateArgs, NumTemplateArgs,
|
||||
CanonicalTemplateArgs, Context);
|
||||
|
||||
// FIXME: Get the canonical template-name
|
||||
QualType CanonType
|
||||
= Context.getTemplateSpecializationType(Name, &CanonicalTemplateArgs[0],
|
||||
CanonicalTemplateArgs.size());
|
||||
|
||||
// Build the dependent template-id type.
|
||||
return Context.getTemplateSpecializationType(Name, TemplateArgs,
|
||||
NumTemplateArgs, CanonType);
|
||||
}
|
||||
|
||||
// Check that the template argument list is well-formed for this
|
||||
// template.
|
||||
|
@ -808,6 +875,57 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,
|
|||
return Result.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
/// \brief Form a dependent template name.
|
||||
///
|
||||
/// This action forms a dependent template name given the template
|
||||
/// name and its (presumably dependent) scope specifier. For
|
||||
/// example, given "MetaFun::template apply", the scope specifier \p
|
||||
/// SS will be "MetaFun::", \p TemplateKWLoc contains the location
|
||||
/// of the "template" keyword, and "apply" is the \p Name.
|
||||
Sema::TemplateTy
|
||||
Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
|
||||
const IdentifierInfo &Name,
|
||||
SourceLocation NameLoc,
|
||||
const CXXScopeSpec &SS) {
|
||||
if (!SS.isSet() || SS.isInvalid())
|
||||
return TemplateTy();
|
||||
|
||||
NestedNameSpecifier *Qualifier
|
||||
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
|
||||
|
||||
// FIXME: member of the current instantiation
|
||||
|
||||
if (!Qualifier->isDependent()) {
|
||||
// C++0x [temp.names]p5:
|
||||
// If a name prefixed by the keyword template is not the name of
|
||||
// a template, the program is ill-formed. [Note: the keyword
|
||||
// template may not be applied to non-template members of class
|
||||
// templates. -end note ] [ Note: as is the case with the
|
||||
// typename prefix, the template prefix is allowed in cases
|
||||
// where it is not strictly necessary; i.e., when the
|
||||
// nested-name-specifier or the expression on the left of the ->
|
||||
// or . is not dependent on a template-parameter, or the use
|
||||
// does not appear in the scope of a template. -end note]
|
||||
//
|
||||
// Note: C++03 was more strict here, because it banned the use of
|
||||
// the "template" keyword prior to a template-name that was not a
|
||||
// dependent name. C++ DR468 relaxed this requirement (the
|
||||
// "template" keyword is now permitted). We follow the C++0x
|
||||
// rules, even in C++03 mode, retroactively applying the DR.
|
||||
TemplateTy Template;
|
||||
TemplateNameKind TNK = isTemplateName(Name, 0, Template, &SS);
|
||||
if (TNK == TNK_Non_template) {
|
||||
Diag(NameLoc, diag::err_template_kw_refers_to_non_template)
|
||||
<< &Name;
|
||||
return TemplateTy();
|
||||
}
|
||||
|
||||
return Template;
|
||||
}
|
||||
|
||||
return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name));
|
||||
}
|
||||
|
||||
/// \brief Check that the given template argument list is well-formed
|
||||
/// for specializing the given template.
|
||||
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
|
|
|
@ -475,7 +475,7 @@ InstantiateTemplateSpecializationType(
|
|||
// FIXME: Need to instantiate into the template name.
|
||||
return SemaRef.CheckTemplateIdType(T->getTemplateName(),
|
||||
Loc,
|
||||
SourceLocation(),
|
||||
SourceLocation(),
|
||||
&InstantiatedTemplateArgs[0],
|
||||
InstantiatedTemplateArgs.size(),
|
||||
SourceLocation());
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// RUN: clang-cc -fsyntax-only %s
|
||||
|
||||
struct add_pointer {
|
||||
template<typename T>
|
||||
struct apply {
|
||||
typedef T* type;
|
||||
};
|
||||
};
|
||||
|
||||
struct add_reference {
|
||||
template<typename T>
|
||||
struct apply {
|
||||
typedef T& type;
|
||||
};
|
||||
};
|
||||
|
||||
template<typename MetaFun, typename T>
|
||||
struct apply1 {
|
||||
typedef typename MetaFun::template apply<T>::type type;
|
||||
};
|
||||
|
||||
#if 0
|
||||
// FIXME: The code below requires template instantiation for dependent
|
||||
// template-names that occur within nested-name-specifiers.
|
||||
int i;
|
||||
|
||||
apply1<add_pointer, int>::type ip = &i;
|
||||
apply1<add_reference, int>::type ir = i;
|
||||
#endif
|
|
@ -42,8 +42,21 @@ namespace N {
|
|||
struct A<int> {
|
||||
struct X;
|
||||
};
|
||||
|
||||
struct B;
|
||||
}
|
||||
|
||||
struct ::N::A<int>::X {
|
||||
int foo;
|
||||
};
|
||||
|
||||
#if 0
|
||||
// FIXME: the following crashes the parser, because Sema has no way to
|
||||
// community that the "dependent" template-name N::template B doesn't
|
||||
// actually refer to a template.
|
||||
template<typename T>
|
||||
struct TestA {
|
||||
typedef typename N::template B<T>::type type; // xpected-error{{'B' following the 'template' keyword does not refer to a template}}
|
||||
// FIXME: should show what B *does* refer to.
|
||||
};
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue