зеркало из https://github.com/microsoft/clang-1.git
A little more scaffolding for parsing templates:
- Template parameter scope to hold the template parameters - Template parameter context for parsing declarators - Actions for template type parameters and non-type template parameters git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60387 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
b85cce6498
Коммит
26236e8b75
|
@ -852,6 +852,37 @@ public:
|
|||
virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl) {
|
||||
}
|
||||
|
||||
//===---------------------------C++ Templates----------------------------===//
|
||||
|
||||
/// ActOnTypeParameter - Called when a C++ template type parameter
|
||||
/// (e.g., "typename T") has been parsed. Typename specifies whether
|
||||
/// the keyword "typename" was used to declare the type parameter
|
||||
/// (otherwise, "class" was used), and KeyLoc is the location of the
|
||||
/// "class" or "typename" keyword. ParamName is the name of the
|
||||
/// parameter (NULL indicates an unnamed template parameter) and
|
||||
/// ParamName is the location of the parameter name (if any).
|
||||
/// If the type parameter has a default argument, it will be added
|
||||
/// later via ActOnTypeParameterDefault.
|
||||
virtual DeclTy *ActOnTypeParameter(Scope *S, bool Typename,
|
||||
SourceLocation KeyLoc,
|
||||
IdentifierInfo *ParamName,
|
||||
SourceLocation ParamNameLoc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ActOnTypeParameterDefault - Adds a default argument (the type
|
||||
/// Default) to the given template type parameter (TypeParam).
|
||||
virtual void ActOnTypeParameterDefault(DeclTy *TypeParam, TypeTy *Default) {
|
||||
}
|
||||
|
||||
/// ActOnNonTypeTemplateParameter - Called when a C++ non-type
|
||||
/// template parameter (e.g., "int Size" in "template<int Size>
|
||||
/// class Array") has been parsed. S is the current scope and D is
|
||||
/// the parsed declarator.
|
||||
virtual DeclTy *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===----------------------- Obj-C Declarations -------------------------===//
|
||||
|
||||
// ActOnStartClassInterface - this action is called immediately after parsing
|
||||
|
|
|
@ -631,7 +631,8 @@ public:
|
|||
MemberContext, // Struct/Union field.
|
||||
BlockContext, // Declaration within a block in a function.
|
||||
ForContext, // Declaration within first part of a for loop.
|
||||
ConditionContext // Condition declaration in a C++ if/switch/while/for.
|
||||
ConditionContext, // Condition declaration in a C++ if/switch/while/for.
|
||||
TemplateParamContext // Within a template parameter list.
|
||||
};
|
||||
|
||||
/// DeclaratorKind - The kind of declarator this represents.
|
||||
|
@ -743,9 +744,11 @@ public:
|
|||
}
|
||||
|
||||
/// mayOmitIdentifier - Return true if the identifier is either optional or
|
||||
/// not allowed. This is true for typenames and prototypes.
|
||||
/// not allowed. This is true for typenames, prototypes, and template
|
||||
/// parameter lists.
|
||||
bool mayOmitIdentifier() const {
|
||||
return Context == TypeNameContext || Context == PrototypeContext;
|
||||
return Context == TypeNameContext || Context == PrototypeContext ||
|
||||
Context == TemplateParamContext;
|
||||
}
|
||||
|
||||
/// mayHaveIdentifier - Return true if the identifier is either optional or
|
||||
|
|
|
@ -54,7 +54,13 @@ public:
|
|||
/// Blocks serve as top-level scopes for some objects like labels, they
|
||||
/// also prevent things like break and continue. BlockScopes have the
|
||||
/// other flags set as well.
|
||||
BlockScope = 0x40
|
||||
BlockScope = 0x40,
|
||||
|
||||
/// TemplateParamScope - This is a scope that corresponds to the
|
||||
/// template parameters of a C++ template. Template parameter
|
||||
/// scope starts at the 'template' keyword and ends when the
|
||||
/// template declaration ends.
|
||||
TemplateParamScope = 0x80
|
||||
};
|
||||
private:
|
||||
/// The parent scope for this scope. This is null for the translation-unit
|
||||
|
@ -172,6 +178,12 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
/// isTemplateParamScope - Return true if this scope is a C++
|
||||
/// template parameter scope.
|
||||
bool isTemplateParamScope() const {
|
||||
return getFlags() & Scope::TemplateParamScope;
|
||||
}
|
||||
|
||||
/// Init - This is used by the parser to implement scope caching.
|
||||
///
|
||||
void Init(Scope *Parent, unsigned ScopeFlags) {
|
||||
|
|
|
@ -40,15 +40,19 @@ Parser::DeclTy *Parser::ParseTemplateDeclaration(unsigned Context) {
|
|||
}
|
||||
SourceLocation TemplateLoc = ConsumeToken();
|
||||
|
||||
// Try to parse the template parameters, and the declaration if successful.
|
||||
if(ParseTemplateParameters(0)) {
|
||||
// For some reason, this is generating a compiler error when parsing the
|
||||
// declaration. Apparently, ParseDeclaration doesn't want to match a
|
||||
// function-definition, but will match a function declaration.
|
||||
// TODO: ParseDeclarationOrFunctionDefinition
|
||||
return ParseDeclaration(Context);
|
||||
}
|
||||
return 0;
|
||||
// Enter template-parameter scope.
|
||||
EnterScope(Scope::TemplateParamScope|Scope::DeclScope);
|
||||
|
||||
// Try to parse the template parameters, and the declaration if
|
||||
// successful.
|
||||
DeclTy *TemplateDecl = 0;
|
||||
if(ParseTemplateParameters(0))
|
||||
TemplateDecl = ParseDeclarationOrFunctionDefinition();
|
||||
|
||||
// Leave template-parameter scope.
|
||||
ExitScope();
|
||||
|
||||
return TemplateDecl;
|
||||
}
|
||||
|
||||
/// ParseTemplateParameters - Parses a template-parameter-list enclosed in
|
||||
|
@ -153,13 +157,19 @@ Parser::DeclTy *Parser::ParseTemplateParameter() {
|
|||
/// 'typename' identifier[opt]
|
||||
/// 'typename' identifier[opt] '=' type-id
|
||||
Parser::DeclTy *Parser::ParseTypeParameter() {
|
||||
SourceLocation keyLoc = ConsumeToken();
|
||||
assert((Tok.is(tok::kw_class) || Tok.is(tok::kw_typename)) &&
|
||||
"A type-parameter starts with 'class' or 'typename'");
|
||||
|
||||
// Consume the 'class' or 'typename' keyword.
|
||||
bool TypenameKeyword = Tok.is(tok::kw_typename);
|
||||
SourceLocation KeyLoc = ConsumeToken();
|
||||
|
||||
// Grab the template parameter name (if given)
|
||||
IdentifierInfo* paramName = 0;
|
||||
SourceLocation NameLoc;
|
||||
IdentifierInfo* ParamName = 0;
|
||||
if(Tok.is(tok::identifier)) {
|
||||
paramName = Tok.getIdentifierInfo();
|
||||
ConsumeToken();
|
||||
ParamName = Tok.getIdentifierInfo();
|
||||
NameLoc = ConsumeToken();
|
||||
} else if(Tok.is(tok::equal) || Tok.is(tok::comma) ||
|
||||
Tok.is(tok::greater)) {
|
||||
// Unnamed template parameter. Don't have to do anything here, just
|
||||
|
@ -169,17 +179,18 @@ Parser::DeclTy *Parser::ParseTypeParameter() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
DeclTy *TypeParam = Actions.ActOnTypeParameter(CurScope, TypenameKeyword,
|
||||
KeyLoc, ParamName, NameLoc);
|
||||
|
||||
// Grab a default type id (if given).
|
||||
TypeTy* defaultType = 0;
|
||||
if(Tok.is(tok::equal)) {
|
||||
ConsumeToken();
|
||||
defaultType = ParseTypeName();
|
||||
if(!defaultType)
|
||||
return 0;
|
||||
SourceLocation EqualLoc = ConsumeToken();
|
||||
TypeTy *DefaultType = ParseTypeName();
|
||||
if(DefaultType)
|
||||
Actions.ActOnTypeParameterDefault(TypeParam, DefaultType);
|
||||
}
|
||||
|
||||
// FIXME: Add an action for type parameters.
|
||||
return 0;
|
||||
return TypeParam;
|
||||
}
|
||||
|
||||
/// ParseTemplateTemplateParameter - Handle the parsing of template
|
||||
|
@ -244,22 +255,21 @@ Parser::DeclTy* Parser::ParseTemplateTemplateParameter() {
|
|||
/// but that didn't work out to well. Instead, this tries to recrate the basic
|
||||
/// parsing of parameter declarations, but tries to constrain it for template
|
||||
/// parameters.
|
||||
/// FIXME: We need to make ParseParameterDeclaration work for non-type
|
||||
/// template parameters, too.
|
||||
Parser::DeclTy* Parser::ParseNonTypeTemplateParameter()
|
||||
{
|
||||
SourceLocation startLoc = Tok.getLocation();
|
||||
/// FIXME: We need to make a ParseParameterDeclaration that works for
|
||||
/// non-type template parameters and normal function parameters.
|
||||
Parser::DeclTy* Parser::ParseNonTypeTemplateParameter() {
|
||||
SourceLocation StartLoc = Tok.getLocation();
|
||||
|
||||
// Parse the declaration-specifiers (i.e., the type).
|
||||
// FIXME:: The type should probably be restricted in some way... Not all
|
||||
// FIXME: The type should probably be restricted in some way... Not all
|
||||
// declarators (parts of declarators?) are accepted for parameters.
|
||||
DeclSpec ds;
|
||||
ParseDeclarationSpecifiers(ds);
|
||||
DeclSpec DS;
|
||||
ParseDeclarationSpecifiers(DS);
|
||||
|
||||
// Parse this as a typename.
|
||||
Declarator decl(ds, Declarator::TypeNameContext);
|
||||
ParseDeclarator(decl);
|
||||
if(ds.getTypeSpecType() == DeclSpec::TST_unspecified && !ds.getTypeRep()) {
|
||||
Declarator ParamDecl(DS, Declarator::TemplateParamContext);
|
||||
ParseDeclarator(ParamDecl);
|
||||
if(DS.getTypeSpecType() == DeclSpec::TST_unspecified && !DS.getTypeRep()) {
|
||||
// This probably shouldn't happen - and it's more of a Sema thing, but
|
||||
// basically we didn't parse the type name because we couldn't associate
|
||||
// it with an AST node. we should just skip to the comma or greater.
|
||||
|
@ -269,11 +279,8 @@ Parser::DeclTy* Parser::ParseNonTypeTemplateParameter()
|
|||
return 0;
|
||||
}
|
||||
|
||||
// If there's an identifier after the typename, parse that as part of the
|
||||
// declarator - or something.
|
||||
if(Tok.is(tok::identifier)) {
|
||||
ConsumeToken();
|
||||
}
|
||||
// Create the parameter.
|
||||
DeclTy *Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl);
|
||||
|
||||
// Is there a default value? Parsing this can be fairly annoying because
|
||||
// we have to stop on the first non-nested (paren'd) '>' as the closure
|
||||
|
@ -283,6 +290,5 @@ Parser::DeclTy* Parser::ParseNonTypeTemplateParameter()
|
|||
SkipUntil(tok::comma, tok::greater, true, true);
|
||||
}
|
||||
|
||||
// FIXME: Add an action for non-type template parameters.
|
||||
return 0;
|
||||
return Param;
|
||||
}
|
||||
|
|
|
@ -13,9 +13,8 @@ template <template <typename> Foo> ; // expected-error {{expected 'class' bef
|
|||
template <typename T> void foo();
|
||||
template <typename T, typename U> void foo();
|
||||
|
||||
// TODO Implement ParseDeclarationOrFunction()
|
||||
// Template function definitions. Not done yet.
|
||||
// template <typename T> void foo() { }
|
||||
// Template function definitions.
|
||||
template <typename T> void foo() { }
|
||||
|
||||
// Template class (forward) declarations
|
||||
template <typename T> struct A;
|
||||
|
|
Загрузка…
Ссылка в новой задаче