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'">;
//===--------------------------------------------------------------------===//
// C99 6.9: External Definitions.
DeclGroupPtrTy ParseExternalDeclaration();
+ bool isDeclarationAfterDeclarator();
+ bool isStartOfFunctionDefinition();
DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(
TemplateParameterLists *TemplateParams = 0,
AccessSpecifier AS = AS_none);
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);
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,
TemplateArgIsTypeList &TemplateArgIsType,
TemplateArgLocationList &TemplateArgLocations);
void *ParseTemplateArgument(bool &ArgIsType);
+ DeclPtrTy ParseExplicitInstantiation(SourceLocation &DeclEnd);
//===--------------------------------------------------------------------===//
// GNU G++: Type Traits [Type-Traits.html in the GCC manual]
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:
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
/// 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
// 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.
} while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template));
// Parse the actual template declaration.
+ return ParseSingleDeclarationAfterTemplate(Context, &ParamLists,
+ SourceLocation(),
+ DeclEnd, AS);
+}
+
+/// \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);
+ }
- // 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());
+ // 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
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);
+}
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
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);
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);
// 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}}
--- /dev/null
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T> int foo(T), bar(T, T); // expected-error{{single entity}}