зеркало из https://github.com/microsoft/clang-1.git
Refactor the parsing of declarations so that template declarations can
parse just a single declaration and provide a reasonable diagnostic when the "only one declarator per template declaration" rule is violated. This eliminates some ugly, ugly hackery where we used to require thatn the layout of a DeclGroup of a single element be the same as the layout of a single declaration. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71596 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
7a574ccd52
Коммит
1426e534b4
|
@ -240,6 +240,9 @@ def err_two_right_angle_brackets_need_space : Error<
|
|||
def warn_cxx0x_right_shift_in_template_arg : Warning<
|
||||
"use of right-shift operator ('>>') in template argument will require "
|
||||
"parentheses in C++0x">;
|
||||
def err_multiple_template_declarators : Error<
|
||||
"%select{a template declaration|an explicit template instantiation}0 can "
|
||||
"only %select{declare|instante}0 a single entity">;
|
||||
|
||||
def err_expected_qualified_after_typename : Error<
|
||||
"expected a qualified name after 'typename'">;
|
||||
|
|
|
@ -550,6 +550,8 @@ private:
|
|||
//===--------------------------------------------------------------------===//
|
||||
// C99 6.9: External Definitions.
|
||||
DeclGroupPtrTy ParseExternalDeclaration();
|
||||
bool isDeclarationAfterDeclarator();
|
||||
bool isStartOfFunctionDefinition();
|
||||
DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(
|
||||
TemplateParameterLists *TemplateParams = 0,
|
||||
AccessSpecifier AS = AS_none);
|
||||
|
@ -816,6 +818,7 @@ private:
|
|||
DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context,
|
||||
SourceLocation &DeclEnd,
|
||||
bool RequireSemi = true);
|
||||
DeclPtrTy ParseDeclarationAfterDeclarator(Declarator &D);
|
||||
DeclGroupPtrTy ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D);
|
||||
DeclPtrTy ParseFunctionStatementBody(DeclPtrTy Decl);
|
||||
DeclPtrTy ParseFunctionTryBlock(DeclPtrTy Decl);
|
||||
|
@ -1052,6 +1055,12 @@ private:
|
|||
DeclPtrTy ParseTemplateDeclarationOrSpecialization(unsigned Context,
|
||||
SourceLocation &DeclEnd,
|
||||
AccessSpecifier AS=AS_none);
|
||||
DeclPtrTy ParseSingleDeclarationAfterTemplate(
|
||||
unsigned Context,
|
||||
TemplateParameterLists *TemplateParams,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation &DeclEnd,
|
||||
AccessSpecifier AS=AS_none);
|
||||
bool ParseTemplateParameters(unsigned Depth,
|
||||
TemplateParameterList &TemplateParams,
|
||||
SourceLocation &LAngleLoc,
|
||||
|
@ -1086,6 +1095,7 @@ private:
|
|||
TemplateArgIsTypeList &TemplateArgIsType,
|
||||
TemplateArgLocationList &TemplateArgLocations);
|
||||
void *ParseTemplateArgument(bool &ArgIsType);
|
||||
DeclPtrTy ParseExplicitInstantiation(SourceLocation &DeclEnd);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// GNU G++: Type Traits [Type-Traits.html in the GCC manual]
|
||||
|
|
|
@ -233,8 +233,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
|
|||
SourceLocation &DeclEnd) {
|
||||
DeclPtrTy SingleDecl;
|
||||
switch (Tok.getKind()) {
|
||||
case tok::kw_export:
|
||||
case tok::kw_template:
|
||||
if (NextToken().isNot(tok::less)) {
|
||||
SingleDecl = ParseExplicitInstantiation(DeclEnd);
|
||||
break;
|
||||
}
|
||||
// Fall through for template declarations and specializations
|
||||
|
||||
case tok::kw_export:
|
||||
SingleDecl = ParseTemplateDeclarationOrSpecialization(Context, DeclEnd);
|
||||
break;
|
||||
case tok::kw_namespace:
|
||||
|
@ -302,15 +308,11 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
|
|||
return DG;
|
||||
}
|
||||
|
||||
|
||||
/// ParseInitDeclaratorListAfterFirstDeclarator - Parse 'declaration' after
|
||||
/// parsing 'declaration-specifiers declarator'. This method is split out this
|
||||
/// way to handle the ambiguity between top-level function-definitions and
|
||||
/// declarations.
|
||||
/// \brief Parse 'declaration' after parsing 'declaration-specifiers
|
||||
/// declarator'. This method parses the remainder of the declaration
|
||||
/// (including any attributes or initializer, among other things) and
|
||||
/// finalizes the declaration.
|
||||
///
|
||||
/// init-declarator-list: [C99 6.7]
|
||||
/// init-declarator
|
||||
/// init-declarator-list ',' init-declarator
|
||||
/// init-declarator: [C99 6.7]
|
||||
/// declarator
|
||||
/// declarator '=' initializer
|
||||
|
@ -327,6 +329,81 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
|
|||
/// According to the standard grammar, =default and =delete are function
|
||||
/// definitions, but that definitely doesn't fit with the parser here.
|
||||
///
|
||||
Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D) {
|
||||
// If a simple-asm-expr is present, parse it.
|
||||
if (Tok.is(tok::kw_asm)) {
|
||||
SourceLocation Loc;
|
||||
OwningExprResult AsmLabel(ParseSimpleAsm(&Loc));
|
||||
if (AsmLabel.isInvalid()) {
|
||||
SkipUntil(tok::semi, true, true);
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
D.setAsmLabel(AsmLabel.release());
|
||||
D.SetRangeEnd(Loc);
|
||||
}
|
||||
|
||||
// If attributes are present, parse them.
|
||||
if (Tok.is(tok::kw___attribute)) {
|
||||
SourceLocation Loc;
|
||||
AttributeList *AttrList = ParseAttributes(&Loc);
|
||||
D.AddAttributes(AttrList, Loc);
|
||||
}
|
||||
|
||||
// Inform the current actions module that we just parsed this declarator.
|
||||
DeclPtrTy ThisDecl = Actions.ActOnDeclarator(CurScope, D);
|
||||
|
||||
// Parse declarator '=' initializer.
|
||||
if (Tok.is(tok::equal)) {
|
||||
ConsumeToken();
|
||||
if (getLang().CPlusPlus0x && Tok.is(tok::kw_delete)) {
|
||||
SourceLocation DelLoc = ConsumeToken();
|
||||
Actions.SetDeclDeleted(ThisDecl, DelLoc);
|
||||
} else {
|
||||
OwningExprResult Init(ParseInitializer());
|
||||
if (Init.isInvalid()) {
|
||||
SkipUntil(tok::semi, true, true);
|
||||
return DeclPtrTy();
|
||||
}
|
||||
Actions.AddInitializerToDecl(ThisDecl, move(Init));
|
||||
}
|
||||
} else if (Tok.is(tok::l_paren)) {
|
||||
// Parse C++ direct initializer: '(' expression-list ')'
|
||||
SourceLocation LParenLoc = ConsumeParen();
|
||||
ExprVector Exprs(Actions);
|
||||
CommaLocsTy CommaLocs;
|
||||
|
||||
if (ParseExpressionList(Exprs, CommaLocs)) {
|
||||
SkipUntil(tok::r_paren);
|
||||
} else {
|
||||
// Match the ')'.
|
||||
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
||||
|
||||
assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
|
||||
"Unexpected number of commas!");
|
||||
Actions.AddCXXDirectInitializerToDecl(ThisDecl, LParenLoc,
|
||||
move_arg(Exprs),
|
||||
&CommaLocs[0], RParenLoc);
|
||||
}
|
||||
} else {
|
||||
Actions.ActOnUninitializedDecl(ThisDecl);
|
||||
}
|
||||
|
||||
return ThisDecl;
|
||||
}
|
||||
|
||||
/// ParseInitDeclaratorListAfterFirstDeclarator - Parse 'declaration' after
|
||||
/// parsing 'declaration-specifiers declarator'. This method is split out this
|
||||
/// way to handle the ambiguity between top-level function-definitions and
|
||||
/// declarations.
|
||||
///
|
||||
/// init-declarator-list: [C99 6.7]
|
||||
/// init-declarator
|
||||
/// init-declarator-list ',' init-declarator
|
||||
///
|
||||
/// According to the standard grammar, =default and =delete are function
|
||||
/// definitions, but that definitely doesn't fit with the parser here.
|
||||
///
|
||||
Parser::DeclGroupPtrTy Parser::
|
||||
ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
|
||||
// Declarators may be grouped together ("int X, *Y, Z();"). Remember the decls
|
||||
|
@ -336,65 +413,9 @@ ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
|
|||
// At this point, we know that it is not a function definition. Parse the
|
||||
// rest of the init-declarator-list.
|
||||
while (1) {
|
||||
// If a simple-asm-expr is present, parse it.
|
||||
if (Tok.is(tok::kw_asm)) {
|
||||
SourceLocation Loc;
|
||||
OwningExprResult AsmLabel(ParseSimpleAsm(&Loc));
|
||||
if (AsmLabel.isInvalid()) {
|
||||
SkipUntil(tok::semi, true, true);
|
||||
return DeclGroupPtrTy();
|
||||
}
|
||||
|
||||
D.setAsmLabel(AsmLabel.release());
|
||||
D.SetRangeEnd(Loc);
|
||||
}
|
||||
|
||||
// If attributes are present, parse them.
|
||||
if (Tok.is(tok::kw___attribute)) {
|
||||
SourceLocation Loc;
|
||||
AttributeList *AttrList = ParseAttributes(&Loc);
|
||||
D.AddAttributes(AttrList, Loc);
|
||||
}
|
||||
|
||||
// Inform the current actions module that we just parsed this declarator.
|
||||
DeclPtrTy ThisDecl = Actions.ActOnDeclarator(CurScope, D);
|
||||
DeclsInGroup.push_back(ThisDecl);
|
||||
|
||||
// Parse declarator '=' initializer.
|
||||
if (Tok.is(tok::equal)) {
|
||||
ConsumeToken();
|
||||
if (getLang().CPlusPlus0x && Tok.is(tok::kw_delete)) {
|
||||
SourceLocation DelLoc = ConsumeToken();
|
||||
Actions.SetDeclDeleted(ThisDecl, DelLoc);
|
||||
} else {
|
||||
OwningExprResult Init(ParseInitializer());
|
||||
if (Init.isInvalid()) {
|
||||
SkipUntil(tok::semi, true, true);
|
||||
return DeclGroupPtrTy();
|
||||
}
|
||||
Actions.AddInitializerToDecl(ThisDecl, move(Init));
|
||||
}
|
||||
} else if (Tok.is(tok::l_paren)) {
|
||||
// Parse C++ direct initializer: '(' expression-list ')'
|
||||
SourceLocation LParenLoc = ConsumeParen();
|
||||
ExprVector Exprs(Actions);
|
||||
CommaLocsTy CommaLocs;
|
||||
|
||||
if (ParseExpressionList(Exprs, CommaLocs)) {
|
||||
SkipUntil(tok::r_paren);
|
||||
} else {
|
||||
// Match the ')'.
|
||||
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
||||
|
||||
assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
|
||||
"Unexpected number of commas!");
|
||||
Actions.AddCXXDirectInitializerToDecl(ThisDecl, LParenLoc,
|
||||
move_arg(Exprs),
|
||||
&CommaLocs[0], RParenLoc);
|
||||
}
|
||||
} else {
|
||||
Actions.ActOnUninitializedDecl(ThisDecl);
|
||||
}
|
||||
DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D);
|
||||
if (ThisDecl.get())
|
||||
DeclsInGroup.push_back(ThisDecl);
|
||||
|
||||
// If we don't have a comma, it is either the end of the list (a ';') or an
|
||||
// error, bail out.
|
||||
|
|
|
@ -95,15 +95,102 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
|
|||
} while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template));
|
||||
|
||||
// Parse the actual template declaration.
|
||||
return ParseSingleDeclarationAfterTemplate(Context, &ParamLists,
|
||||
SourceLocation(),
|
||||
DeclEnd, AS);
|
||||
}
|
||||
|
||||
// FIXME: This accepts template<typename x> int y;
|
||||
// FIXME: Converting DeclGroupPtr to DeclPtr like this is an insanely gruesome
|
||||
// hack, will bring up on cfe-dev.
|
||||
DeclGroupPtrTy DG = ParseDeclarationOrFunctionDefinition(&ParamLists, AS);
|
||||
// FIXME: Should be ';' location not the token after it. Resolve with above
|
||||
// fixmes.
|
||||
DeclEnd = Tok.getLocation();
|
||||
return DeclPtrTy::make(DG.get());
|
||||
/// \brief Parse a single declaration that declares a template,
|
||||
/// template specialization, or explicit instantiation of a template.
|
||||
///
|
||||
/// \param TemplateParams if non-NULL, the template parameter lists
|
||||
/// that preceded this declaration. In this case, the declaration is a
|
||||
/// template declaration, out-of-line definition of a template, or an
|
||||
/// explicit template specialization. When NULL, the declaration is an
|
||||
/// explicit template instantiation.
|
||||
///
|
||||
/// \param TemplateLoc when TemplateParams is NULL, the location of
|
||||
/// the 'template' keyword that indicates that we have an explicit
|
||||
/// template instantiation.
|
||||
///
|
||||
/// \param DeclEnd will receive the source location of the last token
|
||||
/// within this declaration.
|
||||
///
|
||||
/// \param AS the access specifier associated with this
|
||||
/// declaration. Will be AS_none for namespace-scope declarations.
|
||||
///
|
||||
/// \returns the new declaration.
|
||||
Parser::DeclPtrTy
|
||||
Parser::ParseSingleDeclarationAfterTemplate(
|
||||
unsigned Context,
|
||||
TemplateParameterLists *TemplateParams,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation &DeclEnd,
|
||||
AccessSpecifier AS) {
|
||||
// Parse the declaration specifiers.
|
||||
DeclSpec DS;
|
||||
// FIXME: Pass TemplateLoc through for explicit template instantiations
|
||||
ParseDeclarationSpecifiers(DS, TemplateParams, AS);
|
||||
|
||||
if (Tok.is(tok::semi)) {
|
||||
DeclEnd = ConsumeToken();
|
||||
return Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
|
||||
}
|
||||
|
||||
// Parse the declarator.
|
||||
Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context);
|
||||
ParseDeclarator(DeclaratorInfo);
|
||||
// Error parsing the declarator?
|
||||
if (!DeclaratorInfo.hasName()) {
|
||||
// If so, skip until the semi-colon or a }.
|
||||
SkipUntil(tok::r_brace, true, true);
|
||||
if (Tok.is(tok::semi))
|
||||
ConsumeToken();
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
// If we have a declaration or declarator list, handle it.
|
||||
if (isDeclarationAfterDeclarator()) {
|
||||
// Parse this declaration.
|
||||
DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo);
|
||||
|
||||
if (Tok.is(tok::comma)) {
|
||||
Diag(Tok, diag::err_multiple_template_declarators)
|
||||
<< (TemplateParams == 0);
|
||||
SkipUntil(tok::semi, true, false);
|
||||
return ThisDecl;
|
||||
}
|
||||
|
||||
// Eat the semi colon after the declaration.
|
||||
ExpectAndConsume(tok::semi, diag::err_expected_semi_declation);
|
||||
return ThisDecl;
|
||||
}
|
||||
|
||||
if (DeclaratorInfo.isFunctionDeclarator() &&
|
||||
isStartOfFunctionDefinition()) {
|
||||
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
||||
Diag(Tok, diag::err_function_declared_typedef);
|
||||
|
||||
if (Tok.is(tok::l_brace)) {
|
||||
// This recovery skips the entire function body. It would be nice
|
||||
// to simply call ParseFunctionDefinition() below, however Sema
|
||||
// assumes the declarator represents a function, not a typedef.
|
||||
ConsumeBrace();
|
||||
SkipUntil(tok::r_brace, true);
|
||||
} else {
|
||||
SkipUntil(tok::semi);
|
||||
}
|
||||
return DeclPtrTy();
|
||||
}
|
||||
return ParseFunctionDefinition(DeclaratorInfo);
|
||||
}
|
||||
|
||||
if (DeclaratorInfo.isFunctionDeclarator())
|
||||
Diag(Tok, diag::err_expected_fn_body);
|
||||
else
|
||||
Diag(Tok, diag::err_invalid_token_after_toplevel_declarator);
|
||||
SkipUntil(tok::semi);
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
/// ParseTemplateParameters - Parses a template-parameter-list enclosed in
|
||||
|
@ -693,3 +780,16 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
|
|||
return Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater);
|
||||
}
|
||||
|
||||
/// \brief Parse a C++ explicit template instantiation
|
||||
/// (C++ [temp.explicit]).
|
||||
///
|
||||
/// explicit-instantiation:
|
||||
/// 'template' declaration
|
||||
Parser::DeclPtrTy Parser::ParseExplicitInstantiation(SourceLocation &DeclEnd) {
|
||||
assert(Tok.is(tok::kw_template) && NextToken().isNot(tok::less) &&
|
||||
"Token does not start an explicit instantiation.");
|
||||
|
||||
SourceLocation TemplateLoc = ConsumeToken();
|
||||
return ParseSingleDeclarationAfterTemplate(Declarator::FileContext, 0,
|
||||
TemplateLoc, DeclEnd, AS_none);
|
||||
}
|
||||
|
|
|
@ -437,6 +437,29 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
|
|||
return Actions.ConvertDeclToDeclGroup(SingleDecl);
|
||||
}
|
||||
|
||||
/// \brief Determine whether the current token, if it occurs after a
|
||||
/// declarator, continues a declaration or declaration list.
|
||||
bool Parser::isDeclarationAfterDeclarator() {
|
||||
return Tok.is(tok::equal) || // int X()= -> not a function def
|
||||
Tok.is(tok::comma) || // int X(), -> not a function def
|
||||
Tok.is(tok::semi) || // int X(); -> not a function def
|
||||
Tok.is(tok::kw_asm) || // int X() __asm__ -> not a function def
|
||||
Tok.is(tok::kw___attribute) || // int X() __attr__ -> not a function def
|
||||
(getLang().CPlusPlus &&
|
||||
Tok.is(tok::l_paren)); // int X(0) -> not a function def [C++]
|
||||
}
|
||||
|
||||
/// \brief Determine whether the current token, if it occurs after a
|
||||
/// declarator, indicates the start of a function definition.
|
||||
bool Parser::isStartOfFunctionDefinition() {
|
||||
return Tok.is(tok::l_brace) || // int X() {}
|
||||
(!getLang().CPlusPlus &&
|
||||
isDeclarationSpecifier()) || // int X(f) int f; {}
|
||||
(getLang().CPlusPlus &&
|
||||
(Tok.is(tok::colon) || // X() : Base() {} (used for ctors)
|
||||
Tok.is(tok::kw_try))); // X() try { ... }
|
||||
}
|
||||
|
||||
/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or
|
||||
/// a declaration. We can't tell which we have until we read up to the
|
||||
/// compound-statement in function-definition. TemplateParams, if
|
||||
|
@ -514,14 +537,8 @@ Parser::ParseDeclarationOrFunctionDefinition(
|
|||
return DeclGroupPtrTy();
|
||||
}
|
||||
|
||||
// If the declarator is the start of a function definition, handle it.
|
||||
if (Tok.is(tok::equal) || // int X()= -> not a function def
|
||||
Tok.is(tok::comma) || // int X(), -> not a function def
|
||||
Tok.is(tok::semi) || // int X(); -> not a function def
|
||||
Tok.is(tok::kw_asm) || // int X() __asm__ -> not a function def
|
||||
Tok.is(tok::kw___attribute) || // int X() __attr__ -> not a function def
|
||||
(getLang().CPlusPlus &&
|
||||
Tok.is(tok::l_paren))) { // int X(0) -> not a function def [C++]
|
||||
// If we have a declaration or declarator list, handle it.
|
||||
if (isDeclarationAfterDeclarator()) {
|
||||
// Parse the init-declarator-list for a normal declaration.
|
||||
DeclGroupPtrTy DG =
|
||||
ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
|
||||
|
@ -530,14 +547,8 @@ Parser::ParseDeclarationOrFunctionDefinition(
|
|||
return DG;
|
||||
}
|
||||
|
||||
|
||||
if (DeclaratorInfo.isFunctionDeclarator() &&
|
||||
(Tok.is(tok::l_brace) || // int X() {}
|
||||
(!getLang().CPlusPlus &&
|
||||
isDeclarationSpecifier()) || // int X(f) int f; {}
|
||||
(getLang().CPlusPlus &&
|
||||
(Tok.is(tok::colon) || // X() : Base() {} (used for ctors)
|
||||
Tok.is(tok::kw_try))))) { // X() try { ... }
|
||||
isStartOfFunctionDefinition()) {
|
||||
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
||||
Diag(Tok, diag::err_function_declared_typedef);
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
// Errors
|
||||
export class foo { }; // expected-error {{expected template}}
|
||||
template x; // expected-error {{expected '<' after 'template'}} \
|
||||
// expected-error {{C++ requires a type specifier for all declarations}}
|
||||
template x; // expected-error {{C++ requires a type specifier for all declarations}}
|
||||
export template x; // expected-error {{expected '<' after 'template'}} \
|
||||
// expected-note {{exported templates are unsupported}} \
|
||||
// expected-error {{C++ requires a type specifier for all declarations}}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
template<typename T> int foo(T), bar(T, T); // expected-error{{single entity}}
|
Загрузка…
Ссылка в новой задаче