зеркало из https://github.com/microsoft/clang-1.git
Ultrasimplistic sketch for the parsing of C++ template-ids. This won't
become useful or correct until we (1) parse template arguments correctly, (2) have some way to turn template-ids into types, declarators, etc., and (3) have a real representation of templates. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61208 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
80d2f30593
Коммит
d6fb7ef028
|
@ -369,9 +369,12 @@ OBJC2_AT_KEYWORD(dynamic)
|
|||
// bycopy/byref/in/inout/oneway/out?
|
||||
|
||||
ANNOTATION(cxxscope) // annotation for a C++ scope spec, e.g. "::foo::bar::"
|
||||
ANNOTATION(qualtypename) // annotation for a C typedef name, or a C++ (possibly
|
||||
// qualified) typename, e.g. "foo::MyClass"
|
||||
|
||||
ANNOTATION(qualtypename) // annotation for a C typedef name, a C++ (possibly
|
||||
// qualified) typename, e.g. "foo::MyClass", or
|
||||
// template-id that names a type ("std::vector<int>")
|
||||
ANNOTATION(template_id) // annotation for a C++ template-id that names a
|
||||
// function template specialization (not a type),
|
||||
// e.g., "std::swap<int>"
|
||||
#undef ANNOTATION
|
||||
#undef OBJC2_AT_KEYWORD
|
||||
#undef OBJC1_AT_KEYWORD
|
||||
|
|
|
@ -78,7 +78,9 @@ public:
|
|||
bool isNot(tok::TokenKind K) const { return Kind != (unsigned) K; }
|
||||
|
||||
bool isAnnotationToken() const {
|
||||
return is(tok::annot_qualtypename) || is(tok::annot_cxxscope);
|
||||
return is(tok::annot_qualtypename) ||
|
||||
is(tok::annot_cxxscope) ||
|
||||
is(tok::annot_template_id);
|
||||
}
|
||||
|
||||
/// getLocation - Return a source location identifier for the specified
|
||||
|
@ -211,6 +213,28 @@ struct PPConditionalInfo {
|
|||
bool FoundElse;
|
||||
};
|
||||
|
||||
/// TemplateIdAnnotation - Information about a template-id annotation
|
||||
/// token, which contains the template declaration, template
|
||||
/// arguments, and the source locations for important tokens.
|
||||
struct TemplateIdAnnotation {
|
||||
/// TemplateNameLoc - The location of the template name within the
|
||||
/// source.
|
||||
SourceLocation TemplateNameLoc;
|
||||
|
||||
/// Template - The declaration of the template corresponding to the
|
||||
/// template-name. This is an Action::DeclTy*.
|
||||
void *Template;
|
||||
|
||||
/// LAngleLoc - The location of the '<' before the template argument
|
||||
/// list.
|
||||
SourceLocation LAngleLoc;
|
||||
|
||||
/// NumArgs - The number of template arguments. The arguments
|
||||
/// themselves are Action::TemplateArgTy pointers allocated directly
|
||||
/// following the TemplateIdAnnotation structure.
|
||||
unsigned NumArgs;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
|
|
@ -63,6 +63,7 @@ public:
|
|||
typedef void BaseTy;
|
||||
typedef void MemInitTy;
|
||||
typedef void CXXScopeTy;
|
||||
typedef void TemplateArgTy;
|
||||
|
||||
/// Expr/Stmt/Type/BaseResult - Provide a unique type to wrap
|
||||
/// ExprTy/StmtTy/TypeTy/BaseTy, providing strong typing and
|
||||
|
@ -76,27 +77,40 @@ public:
|
|||
/// Same, but with ownership.
|
||||
typedef ASTOwningResult<&ActionBase::DeleteExpr> OwningExprResult;
|
||||
typedef ASTOwningResult<&ActionBase::DeleteStmt> OwningStmtResult;
|
||||
typedef ASTOwningResult<&ActionBase::DeleteTemplateArg>
|
||||
OwningTemplateArgResult;
|
||||
// Note that these will replace ExprResult and StmtResult when the transition
|
||||
// is complete.
|
||||
|
||||
/// Single expressions or statements as arguments.
|
||||
typedef ASTOwningPtr<&ActionBase::DeleteExpr> ExprArg;
|
||||
typedef ASTOwningPtr<&ActionBase::DeleteStmt> StmtArg;
|
||||
typedef ASTOwningPtr<&ActionBase::DeleteTemplateArg> TemplateArgArg;
|
||||
|
||||
/// Multiple expressions or statements as arguments.
|
||||
typedef ASTMultiPtr<&ActionBase::DeleteExpr> MultiExprArg;
|
||||
typedef ASTMultiPtr<&ActionBase::DeleteStmt> MultiStmtArg;
|
||||
|
||||
typedef ASTMultiPtr<&ActionBase::DeleteTemplateArg> MultiTemplateArgArg;
|
||||
|
||||
// Utilities for Action implementations to return smart results.
|
||||
|
||||
OwningExprResult ExprError() { return OwningExprResult(*this, true); }
|
||||
OwningStmtResult StmtError() { return OwningStmtResult(*this, true); }
|
||||
OwningTemplateArgResult TemplateArgError() {
|
||||
return OwningTemplateArgResult(*this, true);
|
||||
}
|
||||
|
||||
OwningExprResult ExprError(const DiagnosticBuilder&) { return ExprError(); }
|
||||
OwningStmtResult StmtError(const DiagnosticBuilder&) { return StmtError(); }
|
||||
OwningTemplateArgResult TemplateArgError(const DiagnosticBuilder&) {
|
||||
return TemplateArgError();
|
||||
}
|
||||
|
||||
OwningExprResult ExprEmpty() { return OwningExprResult(*this, false); }
|
||||
OwningStmtResult StmtEmpty() { return OwningStmtResult(*this, false); }
|
||||
OwningTemplateArgResult TemplateArgEmpty() {
|
||||
return OwningTemplateArgResult(*this, false);
|
||||
}
|
||||
|
||||
/// Statistics.
|
||||
virtual void PrintStats() const {}
|
||||
|
@ -117,6 +131,14 @@ public:
|
|||
virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
|
||||
const CXXScopeSpec *SS = 0) = 0;
|
||||
|
||||
/// isTemplateName - Determines whether the identifier II is a
|
||||
/// template name in the current scope, and returns the template
|
||||
/// declaration if II names a template. An optional CXXScope can be
|
||||
/// passed to indicate the C++ scope in which the identifier will be
|
||||
/// found.
|
||||
virtual DeclTy *isTemplateName(IdentifierInfo &II, Scope *S,
|
||||
const CXXScopeSpec *SS = 0) = 0;
|
||||
|
||||
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
|
||||
/// global scope ('::').
|
||||
virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
|
||||
|
@ -918,6 +940,8 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===----------------------- Obj-C Declarations -------------------------===//
|
||||
|
||||
// ActOnStartClassInterface - this action is called immediately after parsing
|
||||
|
@ -1164,6 +1188,14 @@ public:
|
|||
virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S,
|
||||
const CXXScopeSpec *SS);
|
||||
|
||||
/// isTemplateName - Determines whether the identifier II is a
|
||||
/// template name in the current scope, and returns the template
|
||||
/// declaration if II names a template. An optional CXXScope can be
|
||||
/// passed to indicate the C++ scope in which the identifier will be
|
||||
/// found.
|
||||
virtual DeclTy *isTemplateName(IdentifierInfo &II, Scope *S,
|
||||
const CXXScopeSpec *SS = 0);
|
||||
|
||||
/// ActOnDeclarator - If this is a typedef declarator, we modify the
|
||||
/// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is
|
||||
/// popped.
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace clang
|
|||
// what types are required to be identical for the actions.
|
||||
typedef void ExprTy;
|
||||
typedef void StmtTy;
|
||||
typedef void TemplateArgTy;
|
||||
|
||||
/// ActionResult - This structure is used while parsing/acting on
|
||||
/// expressions, stmts, etc. It encapsulates both the object returned by
|
||||
|
@ -57,6 +58,7 @@ namespace clang
|
|||
/// pointers need access to them.
|
||||
virtual void DeleteExpr(ExprTy *E) {}
|
||||
virtual void DeleteStmt(StmtTy *E) {}
|
||||
virtual void DeleteTemplateArg(TemplateArgTy *E) {}
|
||||
};
|
||||
|
||||
/// ASTDestroyer - The type of an AST node destruction function pointer.
|
||||
|
@ -71,6 +73,9 @@ namespace clang
|
|||
template <> struct DestroyerToUID<&ActionBase::DeleteStmt> {
|
||||
static const unsigned UID = 1;
|
||||
};
|
||||
template <> struct DestroyerToUID<&ActionBase::DeleteTemplateArg> {
|
||||
static const unsigned UID = 1;
|
||||
};
|
||||
|
||||
/// ASTOwningResult - A moveable smart pointer for AST nodes that also
|
||||
/// has an extra flag to indicate an additional success status.
|
||||
|
|
|
@ -78,14 +78,16 @@ public:
|
|||
typedef Action::BaseTy BaseTy;
|
||||
typedef Action::MemInitTy MemInitTy;
|
||||
typedef Action::CXXScopeTy CXXScopeTy;
|
||||
typedef Action::TemplateArgTy TemplateArgTy;
|
||||
|
||||
typedef Action::ExprResult ExprResult;
|
||||
typedef Action::StmtResult StmtResult;
|
||||
typedef Action::BaseResult BaseResult;
|
||||
typedef Action::MemInitResult MemInitResult;
|
||||
typedef Action::ExprResult ExprResult;
|
||||
typedef Action::StmtResult StmtResult;
|
||||
typedef Action::BaseResult BaseResult;
|
||||
typedef Action::MemInitResult MemInitResult;
|
||||
|
||||
typedef Action::OwningExprResult OwningExprResult;
|
||||
typedef Action::OwningStmtResult OwningStmtResult;
|
||||
typedef Action::OwningTemplateArgResult OwningTemplateArgResult;
|
||||
|
||||
typedef Action::ExprArg ExprArg;
|
||||
|
||||
|
@ -100,8 +102,15 @@ public:
|
|||
|
||||
OwningExprResult ExprError() { return OwningExprResult(Actions, true); }
|
||||
OwningStmtResult StmtError() { return OwningStmtResult(Actions, true); }
|
||||
OwningTemplateArgResult TemplateArgError() {
|
||||
return OwningTemplateArgResult(Actions, true);
|
||||
}
|
||||
|
||||
OwningExprResult ExprError(const DiagnosticBuilder &) { return ExprError(); }
|
||||
OwningStmtResult StmtError(const DiagnosticBuilder &) { return StmtError(); }
|
||||
OwningTemplateArgResult TemplateArgError(const DiagnosticBuilder &) {
|
||||
return TemplateArgError();
|
||||
}
|
||||
|
||||
// Parsing methods.
|
||||
|
||||
|
@ -936,6 +945,12 @@ private:
|
|||
DeclTy *ParseTypeParameter();
|
||||
DeclTy *ParseTemplateTemplateParameter();
|
||||
DeclTy *ParseNonTypeTemplateParameter();
|
||||
// C++ 14.3: Template arguments [temp.arg]
|
||||
typedef llvm::SmallVector<TemplateArgTy*, 8> TemplateArgList;
|
||||
void AnnotateTemplateIdToken(DeclTy *Template, const CXXScopeSpec *SS = 0);
|
||||
bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs);
|
||||
OwningTemplateArgResult ParseTemplateArgument();
|
||||
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -73,6 +73,16 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
|
|||
return false;
|
||||
}
|
||||
|
||||
/// isTemplateName - Determines whether the identifier II is a
|
||||
/// template name in the current scope, and returns the template
|
||||
/// declaration if II names a template. An optional CXXScope can be
|
||||
/// passed to indicate the C++ scope in which the identifier will be
|
||||
/// found.
|
||||
Action::DeclTy *MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S,
|
||||
const CXXScopeSpec *SS ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ActOnDeclarator - If this is a typedef declarator, we modify the
|
||||
/// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is
|
||||
/// popped.
|
||||
|
|
|
@ -1452,13 +1452,27 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
|||
|
||||
if (Tok.is(tok::identifier)) {
|
||||
assert(Tok.getIdentifierInfo() && "Not an identifier?");
|
||||
// Determine whether this identifier is a C++ constructor name or
|
||||
// a normal identifier.
|
||||
if (Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope)) {
|
||||
|
||||
// If this identifier is followed by a '<', we may have a template-id.
|
||||
DeclTy *Template;
|
||||
if (getLang().CPlusPlus && NextToken().is(tok::less) &&
|
||||
(Template = Actions.isTemplateName(*Tok.getIdentifierInfo(),
|
||||
CurScope))) {
|
||||
IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
AnnotateTemplateIdToken(Template, 0);
|
||||
// FIXME: Set the declarator to a template-id. How? I don't
|
||||
// know... for now, just use the identifier.
|
||||
D.SetIdentifier(II, Tok.getLocation());
|
||||
}
|
||||
// If this identifier is the name of the current class, it's a
|
||||
// constructor name.
|
||||
else if (getLang().CPlusPlus &&
|
||||
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope))
|
||||
D.setConstructor(Actions.isTypeName(*Tok.getIdentifierInfo(),
|
||||
CurScope),
|
||||
Tok.getLocation());
|
||||
} else
|
||||
// This is a normal identifier.
|
||||
else
|
||||
D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
|
||||
ConsumeToken();
|
||||
goto PastIdentifier;
|
||||
|
|
|
@ -46,8 +46,19 @@ Parser::DeclTy *Parser::ParseTemplateDeclaration(unsigned Context) {
|
|||
// Try to parse the template parameters, and the declaration if
|
||||
// successful.
|
||||
DeclTy *TemplateDecl = 0;
|
||||
if(ParseTemplateParameters(0))
|
||||
if (Tok.is(tok::less) && NextToken().is(tok::greater)) {
|
||||
// This is a template specialization. Just consume the angle
|
||||
// brackets and parse the declaration or function definition that
|
||||
// follows.
|
||||
// FIXME: Record somehow that we're in an explicit specialization.
|
||||
ConsumeToken();
|
||||
ConsumeToken();
|
||||
TemplateParmScope.Exit();
|
||||
TemplateDecl = ParseDeclarationOrFunctionDefinition();
|
||||
} else {
|
||||
if(ParseTemplateParameters(0))
|
||||
TemplateDecl = ParseDeclarationOrFunctionDefinition();
|
||||
}
|
||||
|
||||
return TemplateDecl;
|
||||
}
|
||||
|
@ -243,7 +254,7 @@ Parser::DeclTy* Parser::ParseTemplateTemplateParameter() {
|
|||
|
||||
/// ParseNonTypeTemplateParameter - Handle the parsing of non-type
|
||||
/// template parameters (e.g., in "template<int Size> class array;").
|
||||
|
||||
///
|
||||
/// template-parameter:
|
||||
/// ...
|
||||
/// parameter-declaration
|
||||
|
@ -289,3 +300,96 @@ Parser::DeclTy* Parser::ParseNonTypeTemplateParameter() {
|
|||
|
||||
return Param;
|
||||
}
|
||||
|
||||
/// AnnotateTemplateIdToken - The current token is an identifier that
|
||||
/// refers to the template declaration Template, and is followed by a
|
||||
/// '<'. Turn this template-id into a template-id annotation token.
|
||||
void Parser::AnnotateTemplateIdToken(DeclTy *Template, const CXXScopeSpec *SS) {
|
||||
assert(getLang().CPlusPlus && "Can only annotate template-ids in C++");
|
||||
assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) &&
|
||||
"Parser isn't at the beginning of a template-id");
|
||||
|
||||
// Consume the template-name.
|
||||
SourceLocation TemplateNameLoc = ConsumeToken();
|
||||
|
||||
// Consume the '<'.
|
||||
SourceLocation LAngleLoc = ConsumeToken();
|
||||
|
||||
// Parse the optional template-argument-list.
|
||||
TemplateArgList TemplateArgs;
|
||||
if (Tok.isNot(tok::greater) && ParseTemplateArgumentList(TemplateArgs)) {
|
||||
// Try to find the closing '>'.
|
||||
SkipUntil(tok::greater, true, true);
|
||||
|
||||
// FIXME: What's our recovery strategy for failed template-argument-lists?
|
||||
return;
|
||||
}
|
||||
|
||||
if (Tok.isNot(tok::greater))
|
||||
return;
|
||||
|
||||
// Determine the location of the '>'. We won't actually consume this
|
||||
// token, because we'll be replacing it with the template-id.
|
||||
SourceLocation RAngleLoc = Tok.getLocation();
|
||||
|
||||
Tok.setKind(tok::annot_template_id);
|
||||
Tok.setAnnotationEndLoc(RAngleLoc);
|
||||
Tok.setLocation(TemplateNameLoc);
|
||||
if (SS && SS->isNotEmpty())
|
||||
Tok.setLocation(SS->getBeginLoc());
|
||||
|
||||
TemplateIdAnnotation *TemplateId
|
||||
= (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) +
|
||||
sizeof(TemplateArgTy*) * TemplateArgs.size());
|
||||
TemplateId->TemplateNameLoc = TemplateNameLoc;
|
||||
TemplateId->Template = Template;
|
||||
TemplateId->LAngleLoc = LAngleLoc;
|
||||
TemplateId->NumArgs = TemplateArgs.size();
|
||||
TemplateArgTy **Args = (TemplateArgTy**)(TemplateId + 1);
|
||||
for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
|
||||
Args[Arg] = TemplateArgs[Arg];
|
||||
Tok.setAnnotationValue(TemplateId);
|
||||
|
||||
// In case the tokens were cached, have Preprocessor replace them with the
|
||||
// annotation token.
|
||||
PP.AnnotateCachedTokens(Tok);
|
||||
}
|
||||
|
||||
/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]).
|
||||
///
|
||||
/// template-argument: [C++ 14.2]
|
||||
/// assignment-expression
|
||||
/// type-id
|
||||
/// id-expression
|
||||
Parser::OwningTemplateArgResult Parser::ParseTemplateArgument() {
|
||||
// FIXME: Implement this!
|
||||
return TemplateArgError();
|
||||
}
|
||||
|
||||
/// ParseTemplateArgumentList - Parse a C++ template-argument-list
|
||||
/// (C++ [temp.names]). Returns true if there was an error.
|
||||
///
|
||||
/// template-argument-list: [C++ 14.2]
|
||||
/// template-argument
|
||||
/// template-argument-list ',' template-argument
|
||||
bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
|
||||
while (true) {
|
||||
OwningTemplateArgResult Arg = ParseTemplateArgument();
|
||||
if (Arg.isInvalid()) {
|
||||
SkipUntil(tok::comma, tok::greater, true, true);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
TemplateArgs.push_back(Arg.release());
|
||||
|
||||
// If the next token is a comma, consume it and keep reading
|
||||
// arguments.
|
||||
if (Tok.isNot(tok::comma)) break;
|
||||
|
||||
// Consume the comma.
|
||||
ConsumeToken();
|
||||
}
|
||||
|
||||
return Tok.isNot(tok::greater);
|
||||
}
|
||||
|
||||
|
|
|
@ -722,6 +722,7 @@ Parser::OwningExprResult Parser::ParseSimpleAsm() {
|
|||
/// specifier, and another one to get the actual type inside
|
||||
/// ParseDeclarationSpecifiers).
|
||||
void Parser::TryAnnotateTypeOrScopeToken() {
|
||||
// FIXME: what about template-ids?
|
||||
if (Tok.is(tok::annot_qualtypename) || Tok.is(tok::annot_cxxscope))
|
||||
return;
|
||||
|
||||
|
@ -730,23 +731,39 @@ void Parser::TryAnnotateTypeOrScopeToken() {
|
|||
MaybeParseCXXScopeSpecifier(SS);
|
||||
|
||||
if (Tok.is(tok::identifier)) {
|
||||
TypeTy *Ty = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope, &SS);
|
||||
if (Ty) {
|
||||
// This is a typename. Replace the current token in-place with an
|
||||
// annotation type token.
|
||||
Tok.setKind(tok::annot_qualtypename);
|
||||
Tok.setAnnotationValue(Ty);
|
||||
Tok.setAnnotationEndLoc(Tok.getLocation());
|
||||
if (SS.isNotEmpty()) // it was a C++ qualified type name.
|
||||
Tok.setLocation(SS.getBeginLoc());
|
||||
|
||||
// In case the tokens were cached, have Preprocessor replace them with the
|
||||
// annotation token.
|
||||
PP.AnnotateCachedTokens(Tok);
|
||||
return;
|
||||
DeclTy *Template = 0;
|
||||
// If this is a template-id, annotate the template-id token.
|
||||
if (getLang().CPlusPlus && NextToken().is(tok::less) &&
|
||||
(Template = Actions.isTemplateName(*Tok.getIdentifierInfo(), CurScope,
|
||||
&SS)))
|
||||
AnnotateTemplateIdToken(Template, &SS);
|
||||
else {
|
||||
// Determine whether the identifier is a type name.
|
||||
TypeTy *Ty = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope, &SS);
|
||||
if (Ty) {
|
||||
// This is a typename. Replace the current token in-place with an
|
||||
// annotation type token.
|
||||
Tok.setKind(tok::annot_qualtypename);
|
||||
Tok.setAnnotationValue(Ty);
|
||||
Tok.setAnnotationEndLoc(Tok.getLocation());
|
||||
if (SS.isNotEmpty()) // it was a C++ qualified type name.
|
||||
Tok.setLocation(SS.getBeginLoc());
|
||||
|
||||
// In case the tokens were cached, have Preprocessor replace
|
||||
// them with the annotation token.
|
||||
PP.AnnotateCachedTokens(Tok);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We either have an identifier that is not a type name or we have
|
||||
// just created a template-id that might be a type name. Both
|
||||
// cases will be handled below.
|
||||
}
|
||||
|
||||
// FIXME: check for a template-id token here, and look it up if it
|
||||
// names a type.
|
||||
|
||||
if (SS.isNotEmpty()) {
|
||||
// A C++ scope specifier that isn't followed by a typename.
|
||||
// Push the current token back into the token stream (or revert it if it is
|
||||
|
|
|
@ -1005,6 +1005,8 @@ public:
|
|||
//===--------------------------------------------------------------------===//
|
||||
// C++ Templates [C++ 14]
|
||||
//
|
||||
virtual DeclTy *isTemplateName(IdentifierInfo &II, Scope *S,
|
||||
const CXXScopeSpec *SS = 0);
|
||||
bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
|
||||
virtual DeclTy *ActOnTypeParameter(Scope *S, bool Typename,
|
||||
SourceLocation KeyLoc,
|
||||
|
|
|
@ -18,6 +18,42 @@
|
|||
|
||||
using namespace clang;
|
||||
|
||||
/// isTemplateName - Determines whether the identifier II is a
|
||||
/// template name in the current scope, and returns the template
|
||||
/// declaration if II names a template. An optional CXXScope can be
|
||||
/// passed to indicate the C++ scope in which the identifier will be
|
||||
/// found.
|
||||
Sema::DeclTy *Sema::isTemplateName(IdentifierInfo &II, Scope *S,
|
||||
const CXXScopeSpec *SS) {
|
||||
DeclContext *DC = 0;
|
||||
if (SS) {
|
||||
if (SS->isInvalid())
|
||||
return 0;
|
||||
DC = static_cast<DeclContext*>(SS->getScopeRep());
|
||||
}
|
||||
Decl *IIDecl = LookupDecl(&II, Decl::IDNS_Ordinary, S, DC, false);
|
||||
|
||||
if (IIDecl) {
|
||||
// FIXME: We need to represent templates via some kind of
|
||||
// TemplateDecl, because what follows is a hack that only works in
|
||||
// one specific case.
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(IIDecl)) {
|
||||
if (FD->getType()->isDependentType())
|
||||
return FD;
|
||||
} else if (OverloadedFunctionDecl *Ovl
|
||||
= dyn_cast<OverloadedFunctionDecl>(IIDecl)) {
|
||||
for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
|
||||
FEnd = Ovl->function_end();
|
||||
F != FEnd; ++F) {
|
||||
if ((*F)->getType()->isDependentType())
|
||||
return Ovl;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
|
||||
/// that the template parameter 'PrevDecl' is being shadowed by a new
|
||||
/// declaration at location Loc. Returns true to indicate that this is
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
// RUN: clang -fsyntax-only -verify %s
|
||||
template<int N> void f(int (&array)[N]);
|
||||
|
||||
template<> void f<1>(int (&array)[1]) { }
|
|
@ -1,4 +1,4 @@
|
|||
// RUN clang -fsyntax-only -verify %s
|
||||
// RUN: clang -fsyntax-only -verify %s
|
||||
@protocol P0
|
||||
@end
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче