2006-11-05 15:46:30 +08:00
|
|
|
//===--- ParseDecl.cpp - Declaration Parsing ------------------------------===//
|
2006-07-31 13:13:43 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2006-07-31 13:13:43 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the Declaration portions of the Parser interfaces.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/Parse/Parser.h"
|
2008-08-11 11:45:03 +08:00
|
|
|
#include "clang/Basic/Diagnostic.h"
|
2007-08-26 14:24:45 +08:00
|
|
|
#include "clang/Parse/Scope.h"
|
2008-10-20 14:45:43 +08:00
|
|
|
#include "ExtensionRAIIObject.h"
|
2007-01-23 09:14:52 +08:00
|
|
|
#include "llvm/ADT/SmallSet.h"
|
2006-07-31 13:13:43 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// C99 6.7: Declarations.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2006-08-11 07:56:11 +08:00
|
|
|
/// ParseTypeName
|
|
|
|
/// type-name: [C99 6.7.6]
|
|
|
|
/// specifier-qualifier-list abstract-declarator[opt]
|
2008-11-22 03:14:01 +08:00
|
|
|
///
|
|
|
|
/// Called type-id in C++.
|
|
|
|
/// CXXNewMode is a special flag used by the parser of C++ new-expressions. It
|
|
|
|
/// is simply passed on to ActOnTypeName.
|
|
|
|
Parser::TypeTy *Parser::ParseTypeName(bool CXXNewMode) {
|
2006-08-11 07:56:11 +08:00
|
|
|
// Parse the common declaration-specifiers piece.
|
|
|
|
DeclSpec DS;
|
2006-08-13 09:16:23 +08:00
|
|
|
ParseSpecifierQualifierList(DS);
|
2006-08-11 07:56:11 +08:00
|
|
|
|
|
|
|
// Parse the abstract-declarator, if present.
|
|
|
|
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
|
|
|
|
ParseDeclarator(DeclaratorInfo);
|
2006-08-24 14:37:51 +08:00
|
|
|
|
2008-11-22 03:14:01 +08:00
|
|
|
return Actions.ActOnTypeName(CurScope, DeclaratorInfo, CXXNewMode).Val;
|
2006-08-11 07:56:11 +08:00
|
|
|
}
|
|
|
|
|
2006-08-15 12:10:46 +08:00
|
|
|
/// ParseAttributes - Parse a non-empty attributes list.
|
|
|
|
///
|
|
|
|
/// [GNU] attributes:
|
|
|
|
/// attribute
|
|
|
|
/// attributes attribute
|
|
|
|
///
|
|
|
|
/// [GNU] attribute:
|
|
|
|
/// '__attribute__' '(' '(' attribute-list ')' ')'
|
|
|
|
///
|
|
|
|
/// [GNU] attribute-list:
|
|
|
|
/// attrib
|
|
|
|
/// attribute_list ',' attrib
|
|
|
|
///
|
|
|
|
/// [GNU] attrib:
|
|
|
|
/// empty
|
2007-06-02 01:11:19 +08:00
|
|
|
/// attrib-name
|
|
|
|
/// attrib-name '(' identifier ')'
|
|
|
|
/// attrib-name '(' identifier ',' nonempty-expr-list ')'
|
|
|
|
/// attrib-name '(' argument-expression-list [C99 6.5.2] ')'
|
2006-08-15 12:10:46 +08:00
|
|
|
///
|
2007-06-02 01:11:19 +08:00
|
|
|
/// [GNU] attrib-name:
|
|
|
|
/// identifier
|
|
|
|
/// typespec
|
|
|
|
/// typequal
|
|
|
|
/// storageclass
|
|
|
|
///
|
|
|
|
/// FIXME: The GCC grammar/code for this construct implies we need two
|
|
|
|
/// token lookahead. Comment from gcc: "If they start with an identifier
|
|
|
|
/// which is followed by a comma or close parenthesis, then the arguments
|
|
|
|
/// start with that identifier; otherwise they are an expression list."
|
|
|
|
///
|
|
|
|
/// At the moment, I am not doing 2 token lookahead. I am also unaware of
|
|
|
|
/// any attributes that don't work (based on my limited testing). Most
|
|
|
|
/// attributes are very simple in practice. Until we find a bug, I don't see
|
|
|
|
/// a pressing need to implement the 2 token lookahead.
|
|
|
|
|
2007-06-09 11:39:29 +08:00
|
|
|
AttributeList *Parser::ParseAttributes() {
|
2007-10-10 01:33:22 +08:00
|
|
|
assert(Tok.is(tok::kw___attribute) && "Not an attribute list!");
|
2006-08-15 12:10:46 +08:00
|
|
|
|
2007-06-09 11:39:29 +08:00
|
|
|
AttributeList *CurrAttr = 0;
|
2006-08-15 12:10:46 +08:00
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
while (Tok.is(tok::kw___attribute)) {
|
2007-06-02 01:11:19 +08:00
|
|
|
ConsumeToken();
|
|
|
|
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
|
|
|
|
"attribute")) {
|
|
|
|
SkipUntil(tok::r_paren, true); // skip until ) or ;
|
|
|
|
return CurrAttr;
|
|
|
|
}
|
|
|
|
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) {
|
|
|
|
SkipUntil(tok::r_paren, true); // skip until ) or ;
|
|
|
|
return CurrAttr;
|
|
|
|
}
|
|
|
|
// Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") ))
|
2007-10-10 01:33:22 +08:00
|
|
|
while (Tok.is(tok::identifier) || isDeclarationSpecifier() ||
|
|
|
|
Tok.is(tok::comma)) {
|
2007-06-02 01:11:19 +08:00
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::comma)) {
|
2007-06-02 01:11:19 +08:00
|
|
|
// allows for empty/non-empty attributes. ((__vector_size__(16),,,,))
|
|
|
|
ConsumeToken();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// we have an identifier or declaration specifier (const, int, etc.)
|
|
|
|
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation AttrNameLoc = ConsumeToken();
|
|
|
|
|
|
|
|
// check if we have a "paramterized" attribute
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
2007-06-09 11:39:29 +08:00
|
|
|
ConsumeParen(); // ignore the left paren loc for now
|
2007-06-02 01:11:19 +08:00
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
2007-06-02 01:11:19 +08:00
|
|
|
IdentifierInfo *ParmName = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation ParmLoc = ConsumeToken();
|
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::r_paren)) {
|
2007-06-02 01:11:19 +08:00
|
|
|
// __attribute__(( mode(byte) ))
|
2007-06-09 11:39:29 +08:00
|
|
|
ConsumeParen(); // ignore the right paren loc for now
|
|
|
|
CurrAttr = new AttributeList(AttrName, AttrNameLoc,
|
|
|
|
ParmName, ParmLoc, 0, 0, CurrAttr);
|
2007-10-10 01:33:22 +08:00
|
|
|
} else if (Tok.is(tok::comma)) {
|
2007-06-02 01:11:19 +08:00
|
|
|
ConsumeToken();
|
|
|
|
// __attribute__(( format(printf, 1, 2) ))
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::SmallVector<ExprTy*, 8> ArgExprs;
|
2007-06-02 01:11:19 +08:00
|
|
|
bool ArgExprsOk = true;
|
|
|
|
|
|
|
|
// now parse the non-empty comma separated list of expressions
|
|
|
|
while (1) {
|
|
|
|
ExprResult ArgExpr = ParseAssignmentExpression();
|
|
|
|
if (ArgExpr.isInvalid) {
|
|
|
|
ArgExprsOk = false;
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
ArgExprs.push_back(ArgExpr.Val);
|
|
|
|
}
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-06-02 01:11:19 +08:00
|
|
|
break;
|
|
|
|
ConsumeToken(); // Eat the comma, move to the next argument
|
|
|
|
}
|
2007-10-10 01:33:22 +08:00
|
|
|
if (ArgExprsOk && Tok.is(tok::r_paren)) {
|
2007-06-09 11:39:29 +08:00
|
|
|
ConsumeParen(); // ignore the right paren loc for now
|
|
|
|
CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName,
|
|
|
|
ParmLoc, &ArgExprs[0], ArgExprs.size(), CurrAttr);
|
2007-06-02 01:11:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else { // not an identifier
|
|
|
|
// parse a possibly empty comma separated list of expressions
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::r_paren)) {
|
2007-06-02 01:11:19 +08:00
|
|
|
// __attribute__(( nonnull() ))
|
2007-06-09 11:39:29 +08:00
|
|
|
ConsumeParen(); // ignore the right paren loc for now
|
|
|
|
CurrAttr = new AttributeList(AttrName, AttrNameLoc,
|
|
|
|
0, SourceLocation(), 0, 0, CurrAttr);
|
2007-06-02 01:11:19 +08:00
|
|
|
} else {
|
|
|
|
// __attribute__(( aligned(16) ))
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::SmallVector<ExprTy*, 8> ArgExprs;
|
2007-06-02 01:11:19 +08:00
|
|
|
bool ArgExprsOk = true;
|
|
|
|
|
|
|
|
// now parse the list of expressions
|
|
|
|
while (1) {
|
|
|
|
ExprResult ArgExpr = ParseAssignmentExpression();
|
|
|
|
if (ArgExpr.isInvalid) {
|
|
|
|
ArgExprsOk = false;
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
ArgExprs.push_back(ArgExpr.Val);
|
|
|
|
}
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-06-02 01:11:19 +08:00
|
|
|
break;
|
|
|
|
ConsumeToken(); // Eat the comma, move to the next argument
|
|
|
|
}
|
|
|
|
// Match the ')'.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (ArgExprsOk && Tok.is(tok::r_paren)) {
|
2007-06-09 11:39:29 +08:00
|
|
|
ConsumeParen(); // ignore the right paren loc for now
|
|
|
|
CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
|
|
|
|
SourceLocation(), &ArgExprs[0], ArgExprs.size(),
|
|
|
|
CurrAttr);
|
2007-06-02 01:11:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2007-06-09 11:39:29 +08:00
|
|
|
CurrAttr = new AttributeList(AttrName, AttrNameLoc,
|
|
|
|
0, SourceLocation(), 0, 0, CurrAttr);
|
2007-06-02 01:11:19 +08:00
|
|
|
}
|
|
|
|
}
|
2007-06-07 07:19:11 +08:00
|
|
|
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
|
|
|
|
SkipUntil(tok::r_paren, false);
|
|
|
|
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
|
|
|
|
SkipUntil(tok::r_paren, false);
|
2007-06-02 01:11:19 +08:00
|
|
|
}
|
|
|
|
return CurrAttr;
|
2006-08-15 12:10:46 +08:00
|
|
|
}
|
|
|
|
|
2006-08-10 13:19:57 +08:00
|
|
|
/// ParseDeclaration - Parse a full 'declaration', which consists of
|
|
|
|
/// declaration-specifiers, some number of declarators, and a semicolon.
|
|
|
|
/// 'Context' should be a Declarator::TheContext value.
|
2007-08-25 14:57:03 +08:00
|
|
|
///
|
|
|
|
/// declaration: [C99 6.7]
|
|
|
|
/// block-declaration ->
|
|
|
|
/// simple-declaration
|
|
|
|
/// others [FIXME]
|
|
|
|
/// [C++] namespace-definition
|
|
|
|
/// others... [FIXME]
|
|
|
|
///
|
2006-11-19 10:31:38 +08:00
|
|
|
Parser::DeclTy *Parser::ParseDeclaration(unsigned Context) {
|
2007-08-25 14:57:03 +08:00
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::kw_namespace:
|
|
|
|
return ParseNamespace(Context);
|
|
|
|
default:
|
|
|
|
return ParseSimpleDeclaration(Context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl]
|
|
|
|
/// declaration-specifiers init-declarator-list[opt] ';'
|
|
|
|
///[C90/C++]init-declarator-list ';' [TODO]
|
|
|
|
/// [OMP] threadprivate-directive [TODO]
|
|
|
|
Parser::DeclTy *Parser::ParseSimpleDeclaration(unsigned Context) {
|
2006-08-10 13:19:57 +08:00
|
|
|
// Parse the common declaration-specifiers piece.
|
|
|
|
DeclSpec DS;
|
|
|
|
ParseDeclarationSpecifiers(DS);
|
|
|
|
|
2006-08-14 03:58:17 +08:00
|
|
|
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
|
|
|
|
// declaration-specifiers init-declarator-list[opt] ';'
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2006-08-14 03:58:17 +08:00
|
|
|
ConsumeToken();
|
2006-11-19 10:43:37 +08:00
|
|
|
return Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
|
2006-08-14 03:58:17 +08:00
|
|
|
}
|
|
|
|
|
2006-08-10 13:19:57 +08:00
|
|
|
Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context);
|
|
|
|
ParseDeclarator(DeclaratorInfo);
|
|
|
|
|
2006-11-19 10:31:38 +08:00
|
|
|
return ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
|
2006-08-10 13:19:57 +08:00
|
|
|
}
|
|
|
|
|
2007-08-25 14:57:03 +08:00
|
|
|
|
2006-08-14 08:15:20 +08:00
|
|
|
/// 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
|
|
|
|
/// init-declarator: [C99 6.7]
|
|
|
|
/// declarator
|
|
|
|
/// declarator '=' initializer
|
2006-08-15 11:41:14 +08:00
|
|
|
/// [GNU] declarator simple-asm-expr[opt] attributes[opt]
|
|
|
|
/// [GNU] declarator simple-asm-expr[opt] attributes[opt] '=' initializer
|
2008-10-07 01:10:33 +08:00
|
|
|
/// [C++] declarator initializer[opt]
|
|
|
|
///
|
|
|
|
/// [C++] initializer:
|
|
|
|
/// [C++] '=' initializer-clause
|
|
|
|
/// [C++] '(' expression-list ')'
|
2006-08-14 08:15:20 +08:00
|
|
|
///
|
2006-10-16 08:33:54 +08:00
|
|
|
Parser::DeclTy *Parser::
|
|
|
|
ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
|
|
|
|
|
|
|
|
// Declarators may be grouped together ("int X, *Y, Z();"). Provide info so
|
|
|
|
// that they can be chained properly if the actions want this.
|
|
|
|
Parser::DeclTy *LastDeclInGroup = 0;
|
|
|
|
|
2006-08-10 13:19:57 +08:00
|
|
|
// At this point, we know that it is not a function definition. Parse the
|
|
|
|
// rest of the init-declarator-list.
|
|
|
|
while (1) {
|
2006-08-15 11:41:14 +08:00
|
|
|
// If a simple-asm-expr is present, parse it.
|
2008-08-05 09:35:17 +08:00
|
|
|
if (Tok.is(tok::kw_asm)) {
|
2008-08-06 00:28:08 +08:00
|
|
|
ExprResult AsmLabel = ParseSimpleAsm();
|
2008-08-05 09:35:17 +08:00
|
|
|
if (AsmLabel.isInvalid) {
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-08-06 00:28:08 +08:00
|
|
|
|
|
|
|
D.setAsmLabel(AsmLabel.Val);
|
2008-08-05 09:35:17 +08:00
|
|
|
}
|
2006-08-15 11:41:14 +08:00
|
|
|
|
2006-08-15 12:10:46 +08:00
|
|
|
// If attributes are present, parse them.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::kw___attribute))
|
2007-06-10 07:38:17 +08:00
|
|
|
D.AddAttributes(ParseAttributes());
|
2007-09-12 22:07:44 +08:00
|
|
|
|
|
|
|
// Inform the current actions module that we just parsed this declarator.
|
2008-08-06 00:28:08 +08:00
|
|
|
LastDeclInGroup = Actions.ActOnDeclarator(CurScope, D, LastDeclInGroup);
|
2007-09-12 22:07:44 +08:00
|
|
|
|
2006-08-10 13:19:57 +08:00
|
|
|
// Parse declarator '=' initializer.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::equal)) {
|
2006-08-10 13:19:57 +08:00
|
|
|
ConsumeToken();
|
2008-08-05 09:35:17 +08:00
|
|
|
ExprResult Init = ParseInitializer();
|
2006-10-16 08:33:54 +08:00
|
|
|
if (Init.isInvalid) {
|
2006-08-14 08:15:20 +08:00
|
|
|
SkipUntil(tok::semi);
|
2006-10-16 08:33:54 +08:00
|
|
|
return 0;
|
2006-08-14 08:15:20 +08:00
|
|
|
}
|
2007-09-12 22:07:44 +08:00
|
|
|
Actions.AddInitializerToDecl(LastDeclInGroup, Init.Val);
|
2008-10-07 01:10:33 +08:00
|
|
|
} else if (Tok.is(tok::l_paren)) {
|
|
|
|
// Parse C++ direct initializer: '(' expression-list ')'
|
|
|
|
SourceLocation LParenLoc = ConsumeParen();
|
|
|
|
ExprListTy Exprs;
|
|
|
|
CommaLocsTy CommaLocs;
|
|
|
|
|
|
|
|
bool InvalidExpr = false;
|
|
|
|
if (ParseExpressionList(Exprs, CommaLocs)) {
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
InvalidExpr = true;
|
|
|
|
}
|
|
|
|
// Match the ')'.
|
|
|
|
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
|
|
|
|
|
|
|
if (!InvalidExpr) {
|
|
|
|
assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
|
|
|
|
"Unexpected number of commas!");
|
|
|
|
Actions.AddCXXDirectInitializerToDecl(LastDeclInGroup, LParenLoc,
|
|
|
|
&Exprs[0], Exprs.size(),
|
|
|
|
&CommaLocs[0], RParenLoc);
|
|
|
|
}
|
2008-10-29 08:13:59 +08:00
|
|
|
} else {
|
|
|
|
Actions.ActOnUninitializedDecl(LastDeclInGroup);
|
2006-08-10 13:19:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we don't have a comma, it is either the end of the list (a ';') or an
|
|
|
|
// error, bail out.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2006-08-10 13:19:57 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
// Consume the comma.
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// Parse the next declarator.
|
|
|
|
D.clear();
|
2008-10-20 12:57:38 +08:00
|
|
|
|
|
|
|
// Accept attributes in an init-declarator. In the first declarator in a
|
|
|
|
// declaration, these would be part of the declspec. In subsequent
|
|
|
|
// declarators, they become part of the declarator itself, so that they
|
|
|
|
// don't apply to declarators after *this* one. Examples:
|
|
|
|
// short __attribute__((common)) var; -> declspec
|
|
|
|
// short var __attribute__((common)); -> declarator
|
|
|
|
// short x, __attribute__((common)) var; -> declarator
|
|
|
|
if (Tok.is(tok::kw___attribute))
|
|
|
|
D.AddAttributes(ParseAttributes());
|
|
|
|
|
2006-08-10 13:19:57 +08:00
|
|
|
ParseDeclarator(D);
|
|
|
|
}
|
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2006-08-10 13:19:57 +08:00
|
|
|
ConsumeToken();
|
2007-06-09 08:53:06 +08:00
|
|
|
return Actions.FinalizeDeclaratorGroup(CurScope, LastDeclInGroup);
|
2006-08-10 13:19:57 +08:00
|
|
|
}
|
2008-01-05 07:23:46 +08:00
|
|
|
// If this is an ObjC2 for-each loop, this is a successful declarator
|
|
|
|
// parse. The syntax for these looks like:
|
|
|
|
// 'for' '(' declaration 'in' expr ')' statement
|
2008-01-05 07:04:08 +08:00
|
|
|
if (D.getContext() == Declarator::ForContext && isTokIdentifier_in()) {
|
2008-01-04 01:55:25 +08:00
|
|
|
return Actions.FinalizeDeclaratorGroup(CurScope, LastDeclInGroup);
|
|
|
|
}
|
2007-06-09 08:53:06 +08:00
|
|
|
Diag(Tok, diag::err_parse_error);
|
|
|
|
// Skip to end of block or statement
|
2007-08-22 02:36:18 +08:00
|
|
|
SkipUntil(tok::r_brace, true, true);
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::semi))
|
2007-06-09 08:53:06 +08:00
|
|
|
ConsumeToken();
|
|
|
|
return 0;
|
2006-08-10 13:19:57 +08:00
|
|
|
}
|
|
|
|
|
2006-08-13 09:16:23 +08:00
|
|
|
/// ParseSpecifierQualifierList
|
|
|
|
/// specifier-qualifier-list:
|
|
|
|
/// type-specifier specifier-qualifier-list[opt]
|
|
|
|
/// type-qualifier specifier-qualifier-list[opt]
|
2006-08-15 12:50:22 +08:00
|
|
|
/// [GNU] attributes specifier-qualifier-list[opt]
|
2006-08-13 09:16:23 +08:00
|
|
|
///
|
|
|
|
void Parser::ParseSpecifierQualifierList(DeclSpec &DS) {
|
|
|
|
/// specifier-qualifier-list is a subset of declaration-specifiers. Just
|
|
|
|
/// parse declaration-specifiers and complain about extra stuff.
|
|
|
|
ParseDeclarationSpecifiers(DS);
|
|
|
|
|
|
|
|
// Validate declspec for type-name.
|
|
|
|
unsigned Specs = DS.getParsedSpecifiers();
|
2008-06-05 08:02:44 +08:00
|
|
|
if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers())
|
2006-08-13 09:16:23 +08:00
|
|
|
Diag(Tok, diag::err_typename_requires_specqual);
|
|
|
|
|
2006-11-28 13:12:07 +08:00
|
|
|
// Issue diagnostic and remove storage class if present.
|
2006-08-13 09:16:23 +08:00
|
|
|
if (Specs & DeclSpec::PQ_StorageClassSpecifier) {
|
2006-11-28 13:12:07 +08:00
|
|
|
if (DS.getStorageClassSpecLoc().isValid())
|
|
|
|
Diag(DS.getStorageClassSpecLoc(),diag::err_typename_invalid_storageclass);
|
|
|
|
else
|
|
|
|
Diag(DS.getThreadSpecLoc(), diag::err_typename_invalid_storageclass);
|
2006-11-28 12:33:46 +08:00
|
|
|
DS.ClearStorageClassSpecs();
|
2006-08-13 09:16:23 +08:00
|
|
|
}
|
2006-11-28 13:12:07 +08:00
|
|
|
|
|
|
|
// Issue diagnostic and remove function specfier if present.
|
2006-08-13 09:16:23 +08:00
|
|
|
if (Specs & DeclSpec::PQ_FunctionSpecifier) {
|
2008-10-31 17:07:45 +08:00
|
|
|
if (DS.isInlineSpecified())
|
|
|
|
Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec);
|
|
|
|
if (DS.isVirtualSpecified())
|
|
|
|
Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec);
|
|
|
|
if (DS.isExplicitSpecified())
|
|
|
|
Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
|
2006-11-28 12:33:46 +08:00
|
|
|
DS.ClearFunctionSpecs();
|
2006-08-13 09:16:23 +08:00
|
|
|
}
|
|
|
|
}
|
2006-08-10 13:19:57 +08:00
|
|
|
|
2006-07-31 13:13:43 +08:00
|
|
|
/// ParseDeclarationSpecifiers
|
|
|
|
/// declaration-specifiers: [C99 6.7]
|
2006-08-13 08:12:11 +08:00
|
|
|
/// storage-class-specifier declaration-specifiers[opt]
|
|
|
|
/// type-specifier declaration-specifiers[opt]
|
|
|
|
/// [C99] function-specifier declaration-specifiers[opt]
|
2006-08-15 12:50:22 +08:00
|
|
|
/// [GNU] attributes declaration-specifiers[opt]
|
2006-07-31 13:13:43 +08:00
|
|
|
///
|
2006-08-05 11:28:50 +08:00
|
|
|
/// storage-class-specifier: [C99 6.7.1]
|
2006-08-04 13:25:55 +08:00
|
|
|
/// 'typedef'
|
|
|
|
/// 'extern'
|
|
|
|
/// 'static'
|
|
|
|
/// 'auto'
|
|
|
|
/// 'register'
|
2008-11-15 07:42:31 +08:00
|
|
|
/// [C++] 'mutable'
|
2006-08-04 13:25:55 +08:00
|
|
|
/// [GNU] '__thread'
|
2006-08-04 12:39:53 +08:00
|
|
|
/// function-specifier: [C99 6.7.4]
|
2006-08-13 08:12:11 +08:00
|
|
|
/// [C99] 'inline'
|
2008-10-31 17:07:45 +08:00
|
|
|
/// [C++] 'virtual'
|
|
|
|
/// [C++] 'explicit'
|
2006-08-04 12:39:53 +08:00
|
|
|
///
|
|
|
|
void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) {
|
2008-03-13 14:29:04 +08:00
|
|
|
DS.SetRangeStart(Tok.getLocation());
|
2006-07-31 13:13:43 +08:00
|
|
|
while (1) {
|
2006-08-04 13:25:55 +08:00
|
|
|
int isInvalid = false;
|
2006-08-04 12:39:53 +08:00
|
|
|
const char *PrevSpec = 0;
|
2006-11-28 13:05:08 +08:00
|
|
|
SourceLocation Loc = Tok.getLocation();
|
2008-11-07 23:42:26 +08:00
|
|
|
|
2008-11-09 00:45:02 +08:00
|
|
|
// Only annotate C++ scope. Allow class-name as an identifier in case
|
|
|
|
// it's a constructor.
|
|
|
|
TryAnnotateScopeToken();
|
|
|
|
|
2006-07-31 13:13:43 +08:00
|
|
|
switch (Tok.getKind()) {
|
2008-11-07 23:42:26 +08:00
|
|
|
default:
|
|
|
|
// Try to parse a type-specifier; if we found one, continue.
|
|
|
|
if (MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec))
|
|
|
|
continue;
|
|
|
|
|
2008-07-26 08:20:22 +08:00
|
|
|
DoneWithDeclSpec:
|
2006-08-04 12:39:53 +08:00
|
|
|
// If this is not a declaration specifier token, we're done reading decl
|
|
|
|
// specifiers. First verify that DeclSpec's are consistent.
|
2007-12-12 05:27:55 +08:00
|
|
|
DS.Finish(Diags, PP.getSourceManager(), getLang());
|
2006-08-04 12:39:53 +08:00
|
|
|
return;
|
2008-11-09 00:45:02 +08:00
|
|
|
|
|
|
|
case tok::annot_cxxscope: {
|
|
|
|
if (DS.hasTypeSpecifier())
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
|
|
|
// We are looking for a qualified typename.
|
|
|
|
if (NextToken().isNot(tok::identifier))
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
|
|
|
CXXScopeSpec SS;
|
|
|
|
SS.setScopeRep(Tok.getAnnotationValue());
|
|
|
|
SS.setRange(Tok.getAnnotationRange());
|
|
|
|
|
|
|
|
// If the next token is the name of the class type that the C++ scope
|
|
|
|
// denotes, followed by a '(', then this is a constructor declaration.
|
|
|
|
// We're done with the decl-specifiers.
|
|
|
|
if (Actions.isCurrentClassName(*NextToken().getIdentifierInfo(),
|
|
|
|
CurScope, &SS) &&
|
|
|
|
GetLookAheadToken(2).is(tok::l_paren))
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
|
|
|
TypeTy *TypeRep = Actions.isTypeName(*NextToken().getIdentifierInfo(),
|
|
|
|
CurScope, &SS);
|
|
|
|
if (TypeRep == 0)
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
|
|
|
ConsumeToken(); // The C++ scope.
|
|
|
|
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec,
|
|
|
|
TypeRep);
|
|
|
|
if (isInvalid)
|
|
|
|
break;
|
|
|
|
|
|
|
|
DS.SetRangeEnd(Tok.getLocation());
|
|
|
|
ConsumeToken(); // The typename.
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-07-26 09:18:38 +08:00
|
|
|
// typedef-name
|
|
|
|
case tok::identifier: {
|
|
|
|
// This identifier can only be a typedef name if we haven't already seen
|
|
|
|
// a type-specifier. Without this check we misparse:
|
|
|
|
// typedef int X; struct Y { short X; }; as 'short int'.
|
|
|
|
if (DS.hasTypeSpecifier())
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
|
|
|
// It has to be available as a typedef too!
|
2008-08-01 18:35:27 +08:00
|
|
|
TypeTy *TypeRep = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope);
|
2008-07-26 09:18:38 +08:00
|
|
|
if (TypeRep == 0)
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
2008-10-31 17:07:45 +08:00
|
|
|
// C++: If the identifier is actually the name of the class type
|
|
|
|
// being defined and the next token is a '(', then this is a
|
|
|
|
// constructor declaration. We're done with the decl-specifiers
|
|
|
|
// and will treat this token as an identifier.
|
|
|
|
if (getLang().CPlusPlus &&
|
|
|
|
CurScope->isCXXClassScope() &&
|
|
|
|
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) &&
|
|
|
|
NextToken().getKind() == tok::l_paren)
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
2008-07-26 09:18:38 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec,
|
|
|
|
TypeRep);
|
|
|
|
if (isInvalid)
|
|
|
|
break;
|
|
|
|
|
|
|
|
DS.SetRangeEnd(Tok.getLocation());
|
|
|
|
ConsumeToken(); // The identifier
|
|
|
|
|
|
|
|
// Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
|
|
|
|
// is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
|
|
|
|
// Objective-C interface. If we don't have Objective-C or a '<', this is
|
|
|
|
// just a normal reference to a typedef name.
|
|
|
|
if (!Tok.is(tok::less) || !getLang().ObjC1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
SourceLocation EndProtoLoc;
|
2008-07-26 09:53:50 +08:00
|
|
|
llvm::SmallVector<DeclTy *, 8> ProtocolDecl;
|
2008-07-26 12:03:38 +08:00
|
|
|
ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
|
2008-07-26 09:53:50 +08:00
|
|
|
DS.setProtocolQualifiers(&ProtocolDecl[0], ProtocolDecl.size());
|
2008-07-26 09:18:38 +08:00
|
|
|
|
|
|
|
DS.SetRangeEnd(EndProtoLoc);
|
|
|
|
|
2008-09-22 18:28:57 +08:00
|
|
|
// Need to support trailing type qualifiers (e.g. "id<p> const").
|
|
|
|
// If a type specifier follows, it will be diagnosed elsewhere.
|
|
|
|
continue;
|
2008-07-26 09:18:38 +08:00
|
|
|
}
|
2006-08-15 12:50:22 +08:00
|
|
|
// GNU attributes support.
|
|
|
|
case tok::kw___attribute:
|
2007-06-10 07:38:17 +08:00
|
|
|
DS.AddAttributes(ParseAttributes());
|
2006-10-17 11:01:08 +08:00
|
|
|
continue;
|
2006-08-05 11:28:50 +08:00
|
|
|
|
|
|
|
// storage-class-specifier
|
|
|
|
case tok::kw_typedef:
|
2006-11-28 13:05:08 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec);
|
2006-08-05 11:28:50 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_extern:
|
2006-11-28 12:50:12 +08:00
|
|
|
if (DS.isThreadSpecified())
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::ext_thread_before) << "extern";
|
2006-11-28 13:05:08 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec);
|
2006-08-05 11:28:50 +08:00
|
|
|
break;
|
2007-12-18 08:16:02 +08:00
|
|
|
case tok::kw___private_extern__:
|
2008-04-06 14:57:35 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc,
|
|
|
|
PrevSpec);
|
2007-12-18 08:16:02 +08:00
|
|
|
break;
|
2006-08-05 11:28:50 +08:00
|
|
|
case tok::kw_static:
|
2006-11-28 12:50:12 +08:00
|
|
|
if (DS.isThreadSpecified())
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::ext_thread_before) << "static";
|
2006-11-28 13:05:08 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec);
|
2006-08-05 11:28:50 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_auto:
|
2006-11-28 13:05:08 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec);
|
2006-08-05 11:28:50 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_register:
|
2006-11-28 13:05:08 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec);
|
2006-08-05 11:28:50 +08:00
|
|
|
break;
|
2008-11-15 07:42:31 +08:00
|
|
|
case tok::kw_mutable:
|
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec);
|
|
|
|
break;
|
2006-08-05 11:28:50 +08:00
|
|
|
case tok::kw___thread:
|
2006-11-28 13:05:08 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec)*2;
|
2006-08-05 11:28:50 +08:00
|
|
|
break;
|
|
|
|
|
2007-07-31 20:34:36 +08:00
|
|
|
continue;
|
2008-11-07 23:42:26 +08:00
|
|
|
|
2006-08-04 12:39:53 +08:00
|
|
|
// function-specifier
|
|
|
|
case tok::kw_inline:
|
2006-11-28 13:12:07 +08:00
|
|
|
isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec);
|
2006-08-04 12:39:53 +08:00
|
|
|
break;
|
2008-10-31 17:07:45 +08:00
|
|
|
|
|
|
|
case tok::kw_virtual:
|
|
|
|
isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::kw_explicit:
|
|
|
|
isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec);
|
|
|
|
break;
|
2008-06-05 08:02:44 +08:00
|
|
|
|
|
|
|
case tok::less:
|
2008-07-26 09:18:38 +08:00
|
|
|
// GCC ObjC supports types like "<SomeProtocol>" as a synonym for
|
2008-07-26 08:20:22 +08:00
|
|
|
// "id<SomeProtocol>". This is hopelessly old fashioned and dangerous,
|
|
|
|
// but we support it.
|
2008-07-26 09:18:38 +08:00
|
|
|
if (DS.hasTypeSpecifier() || !getLang().ObjC1)
|
2008-07-26 08:20:22 +08:00
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
|
|
|
{
|
|
|
|
SourceLocation EndProtoLoc;
|
2008-07-26 09:53:50 +08:00
|
|
|
llvm::SmallVector<DeclTy *, 8> ProtocolDecl;
|
2008-07-26 12:03:38 +08:00
|
|
|
ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
|
2008-07-26 09:53:50 +08:00
|
|
|
DS.setProtocolQualifiers(&ProtocolDecl[0], ProtocolDecl.size());
|
2008-07-26 09:18:38 +08:00
|
|
|
DS.SetRangeEnd(EndProtoLoc);
|
|
|
|
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id)
|
|
|
|
<< SourceRange(Loc, EndProtoLoc);
|
2008-09-22 18:28:57 +08:00
|
|
|
// Need to support trailing type qualifiers (e.g. "id<p> const").
|
|
|
|
// If a type specifier follows, it will be diagnosed elsewhere.
|
|
|
|
continue;
|
2008-06-05 08:02:44 +08:00
|
|
|
}
|
2006-07-31 13:13:43 +08:00
|
|
|
}
|
2006-08-04 12:39:53 +08:00
|
|
|
// If the specifier combination wasn't legal, issue a diagnostic.
|
|
|
|
if (isInvalid) {
|
|
|
|
assert(PrevSpec && "Method did not return previous specifier!");
|
2008-11-18 15:48:38 +08:00
|
|
|
// Pick between error or extwarn.
|
|
|
|
unsigned DiagID = isInvalid == 1 ? diag::err_invalid_decl_spec_combination
|
|
|
|
: diag::ext_duplicate_declspec;
|
|
|
|
Diag(Tok, DiagID) << PrevSpec;
|
2006-08-04 12:39:53 +08:00
|
|
|
}
|
2008-03-13 14:29:04 +08:00
|
|
|
DS.SetRangeEnd(Tok.getLocation());
|
2006-08-04 12:39:53 +08:00
|
|
|
ConsumeToken();
|
2006-07-31 13:13:43 +08:00
|
|
|
}
|
|
|
|
}
|
2008-11-07 23:42:26 +08:00
|
|
|
/// MaybeParseTypeSpecifier - Try to parse a single type-specifier. We
|
|
|
|
/// primarily follow the C++ grammar with additions for C99 and GNU,
|
|
|
|
/// which together subsume the C grammar. Note that the C++
|
|
|
|
/// type-specifier also includes the C type-qualifier (for const,
|
|
|
|
/// volatile, and C99 restrict). Returns true if a type-specifier was
|
|
|
|
/// found (and parsed), false otherwise.
|
|
|
|
///
|
|
|
|
/// type-specifier: [C++ 7.1.5]
|
|
|
|
/// simple-type-specifier
|
|
|
|
/// class-specifier
|
|
|
|
/// enum-specifier
|
|
|
|
/// elaborated-type-specifier [TODO]
|
|
|
|
/// cv-qualifier
|
|
|
|
///
|
|
|
|
/// cv-qualifier: [C++ 7.1.5.1]
|
|
|
|
/// 'const'
|
|
|
|
/// 'volatile'
|
|
|
|
/// [C99] 'restrict'
|
|
|
|
///
|
|
|
|
/// simple-type-specifier: [ C++ 7.1.5.2]
|
|
|
|
/// '::'[opt] nested-name-specifier[opt] type-name [TODO]
|
|
|
|
/// '::'[opt] nested-name-specifier 'template' template-id [TODO]
|
|
|
|
/// 'char'
|
|
|
|
/// 'wchar_t'
|
|
|
|
/// 'bool'
|
|
|
|
/// 'short'
|
|
|
|
/// 'int'
|
|
|
|
/// 'long'
|
|
|
|
/// 'signed'
|
|
|
|
/// 'unsigned'
|
|
|
|
/// 'float'
|
|
|
|
/// 'double'
|
|
|
|
/// 'void'
|
|
|
|
/// [C99] '_Bool'
|
|
|
|
/// [C99] '_Complex'
|
|
|
|
/// [C99] '_Imaginary' // Removed in TC2?
|
|
|
|
/// [GNU] '_Decimal32'
|
|
|
|
/// [GNU] '_Decimal64'
|
|
|
|
/// [GNU] '_Decimal128'
|
|
|
|
/// [GNU] typeof-specifier
|
|
|
|
/// [OBJC] class-name objc-protocol-refs[opt] [TODO]
|
|
|
|
/// [OBJC] typedef-name objc-protocol-refs[opt] [TODO]
|
|
|
|
bool Parser::MaybeParseTypeSpecifier(DeclSpec &DS, int& isInvalid,
|
|
|
|
const char *&PrevSpec) {
|
2008-11-09 00:45:02 +08:00
|
|
|
// Annotate typenames and C++ scope specifiers.
|
|
|
|
TryAnnotateTypeOrScopeToken();
|
|
|
|
|
2008-11-07 23:42:26 +08:00
|
|
|
SourceLocation Loc = Tok.getLocation();
|
|
|
|
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
// simple-type-specifier:
|
2008-11-09 00:45:02 +08:00
|
|
|
case tok::annot_qualtypename: {
|
2008-11-07 23:42:26 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec,
|
2008-11-09 00:45:02 +08:00
|
|
|
Tok.getAnnotationValue());
|
|
|
|
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
|
|
|
|
ConsumeToken(); // The typename
|
2008-11-07 23:42:26 +08:00
|
|
|
|
|
|
|
// Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
|
|
|
|
// is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
|
|
|
|
// Objective-C interface. If we don't have Objective-C or a '<', this is
|
|
|
|
// just a normal reference to a typedef name.
|
|
|
|
if (!Tok.is(tok::less) || !getLang().ObjC1)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
SourceLocation EndProtoLoc;
|
|
|
|
llvm::SmallVector<DeclTy *, 8> ProtocolDecl;
|
|
|
|
ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
|
|
|
|
DS.setProtocolQualifiers(&ProtocolDecl[0], ProtocolDecl.size());
|
|
|
|
|
|
|
|
DS.SetRangeEnd(EndProtoLoc);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
case tok::kw_short:
|
|
|
|
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_long:
|
|
|
|
if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
|
|
|
|
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
|
|
|
|
else
|
|
|
|
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_signed:
|
|
|
|
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_unsigned:
|
|
|
|
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw__Complex:
|
|
|
|
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw__Imaginary:
|
|
|
|
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_void:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_char:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_int:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_float:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_double:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_wchar_t:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_bool:
|
|
|
|
case tok::kw__Bool:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw__Decimal32:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw__Decimal64:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw__Decimal128:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec);
|
|
|
|
break;
|
|
|
|
|
|
|
|
// class-specifier:
|
|
|
|
case tok::kw_class:
|
|
|
|
case tok::kw_struct:
|
|
|
|
case tok::kw_union:
|
|
|
|
ParseClassSpecifier(DS);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// enum-specifier:
|
|
|
|
case tok::kw_enum:
|
|
|
|
ParseEnumSpecifier(DS);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// cv-qualifier:
|
|
|
|
case tok::kw_const:
|
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec,
|
|
|
|
getLang())*2;
|
|
|
|
break;
|
|
|
|
case tok::kw_volatile:
|
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
|
|
|
|
getLang())*2;
|
|
|
|
break;
|
|
|
|
case tok::kw_restrict:
|
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
|
|
|
|
getLang())*2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// GNU typeof support.
|
|
|
|
case tok::kw_typeof:
|
|
|
|
ParseTypeofSpecifier(DS);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// Not a type-specifier; do nothing.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the specifier combination wasn't legal, issue a diagnostic.
|
|
|
|
if (isInvalid) {
|
|
|
|
assert(PrevSpec && "Method did not return previous specifier!");
|
2008-11-18 15:48:38 +08:00
|
|
|
// Pick between error or extwarn.
|
|
|
|
unsigned DiagID = isInvalid == 1 ? diag::err_invalid_decl_spec_combination
|
|
|
|
: diag::ext_duplicate_declspec;
|
|
|
|
Diag(Tok, DiagID) << PrevSpec;
|
2008-11-07 23:42:26 +08:00
|
|
|
}
|
|
|
|
DS.SetRangeEnd(Tok.getLocation());
|
|
|
|
ConsumeToken(); // whatever we parsed above.
|
|
|
|
return true;
|
|
|
|
}
|
2006-07-31 13:13:43 +08:00
|
|
|
|
2007-10-29 12:42:53 +08:00
|
|
|
/// ParseStructDeclaration - Parse a struct declaration without the terminating
|
|
|
|
/// semicolon.
|
|
|
|
///
|
2007-01-23 12:38:16 +08:00
|
|
|
/// struct-declaration:
|
2007-10-29 12:42:53 +08:00
|
|
|
/// specifier-qualifier-list struct-declarator-list
|
2007-06-09 13:59:07 +08:00
|
|
|
/// [GNU] __extension__ struct-declaration
|
2007-10-29 12:42:53 +08:00
|
|
|
/// [GNU] specifier-qualifier-list
|
2007-01-23 12:38:16 +08:00
|
|
|
/// struct-declarator-list:
|
|
|
|
/// struct-declarator
|
|
|
|
/// struct-declarator-list ',' struct-declarator
|
|
|
|
/// [GNU] struct-declarator-list ',' attributes[opt] struct-declarator
|
|
|
|
/// struct-declarator:
|
|
|
|
/// declarator
|
|
|
|
/// [GNU] declarator attributes[opt]
|
|
|
|
/// declarator[opt] ':' constant-expression
|
|
|
|
/// [GNU] declarator[opt] ':' constant-expression attributes[opt]
|
|
|
|
///
|
2008-04-10 14:46:29 +08:00
|
|
|
void Parser::
|
|
|
|
ParseStructDeclaration(DeclSpec &DS,
|
|
|
|
llvm::SmallVectorImpl<FieldDeclarator> &Fields) {
|
2008-10-20 14:45:43 +08:00
|
|
|
if (Tok.is(tok::kw___extension__)) {
|
|
|
|
// __extension__ silences extension warnings in the subexpression.
|
|
|
|
ExtensionRAIIObject O(Diags); // Use RAII to do this.
|
2007-08-21 06:28:22 +08:00
|
|
|
ConsumeToken();
|
2008-10-20 14:45:43 +08:00
|
|
|
return ParseStructDeclaration(DS, Fields);
|
|
|
|
}
|
2007-08-21 06:28:22 +08:00
|
|
|
|
|
|
|
// Parse the common specifier-qualifiers-list piece.
|
2008-04-10 14:15:14 +08:00
|
|
|
SourceLocation DSStart = Tok.getLocation();
|
2007-08-21 06:28:22 +08:00
|
|
|
ParseSpecifierQualifierList(DS);
|
|
|
|
|
|
|
|
// If there are no declarators, issue a warning.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2008-04-10 14:15:14 +08:00
|
|
|
Diag(DSStart, diag::w_no_declarators);
|
2007-08-21 06:28:22 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read struct-declarators until we find the semicolon.
|
2008-04-11 00:37:40 +08:00
|
|
|
Fields.push_back(FieldDeclarator(DS));
|
2007-08-21 06:28:22 +08:00
|
|
|
while (1) {
|
2008-04-10 14:46:29 +08:00
|
|
|
FieldDeclarator &DeclaratorInfo = Fields.back();
|
|
|
|
|
2007-08-21 06:28:22 +08:00
|
|
|
/// struct-declarator: declarator
|
|
|
|
/// struct-declarator: declarator[opt] ':' constant-expression
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.isNot(tok::colon))
|
2008-04-10 14:46:29 +08:00
|
|
|
ParseDeclarator(DeclaratorInfo.D);
|
2007-08-21 06:28:22 +08:00
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::colon)) {
|
2007-08-21 06:28:22 +08:00
|
|
|
ConsumeToken();
|
|
|
|
ExprResult Res = ParseConstantExpression();
|
2008-04-10 14:15:14 +08:00
|
|
|
if (Res.isInvalid)
|
2007-08-21 06:28:22 +08:00
|
|
|
SkipUntil(tok::semi, true, true);
|
2008-04-10 14:15:14 +08:00
|
|
|
else
|
2008-04-10 14:46:29 +08:00
|
|
|
DeclaratorInfo.BitfieldSize = Res.Val;
|
2007-08-21 06:28:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If attributes exist after the declarator, parse them.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::kw___attribute))
|
2008-04-10 14:46:29 +08:00
|
|
|
DeclaratorInfo.D.AddAttributes(ParseAttributes());
|
2007-08-21 06:28:22 +08:00
|
|
|
|
|
|
|
// If we don't have a comma, it is either the end of the list (a ';')
|
|
|
|
// or an error, bail out.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-10-29 12:42:53 +08:00
|
|
|
return;
|
2007-08-21 06:28:22 +08:00
|
|
|
|
|
|
|
// Consume the comma.
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// Parse the next declarator.
|
2008-04-11 00:37:40 +08:00
|
|
|
Fields.push_back(FieldDeclarator(DS));
|
2007-08-21 06:28:22 +08:00
|
|
|
|
|
|
|
// Attributes are only allowed on the second declarator.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::kw___attribute))
|
2008-04-10 14:46:29 +08:00
|
|
|
Fields.back().D.AddAttributes(ParseAttributes());
|
2007-08-21 06:28:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseStructUnionBody
|
|
|
|
/// struct-contents:
|
|
|
|
/// struct-declaration-list
|
|
|
|
/// [EXT] empty
|
|
|
|
/// [GNU] "struct-declaration-list" without terminatoring ';'
|
|
|
|
/// struct-declaration-list:
|
|
|
|
/// struct-declaration
|
|
|
|
/// struct-declaration-list struct-declaration
|
2008-06-22 03:39:06 +08:00
|
|
|
/// [OBC] '@' 'defs' '(' class-name ')'
|
2007-08-21 06:28:22 +08:00
|
|
|
///
|
2007-01-24 07:42:53 +08:00
|
|
|
void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
|
|
|
|
unsigned TagType, DeclTy *TagDecl) {
|
2007-01-23 12:38:16 +08:00
|
|
|
SourceLocation LBraceLoc = ConsumeBrace();
|
|
|
|
|
2007-01-24 04:11:08 +08:00
|
|
|
// Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in
|
|
|
|
// C++.
|
2008-04-14 05:30:24 +08:00
|
|
|
if (Tok.is(tok::r_brace) && !getLang().CPlusPlus)
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::ext_empty_struct_union_enum)
|
|
|
|
<< DeclSpec::getSpecifierName((DeclSpec::TST)TagType);
|
2007-01-24 04:11:08 +08:00
|
|
|
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::SmallVector<DeclTy*, 32> FieldDecls;
|
2008-04-10 14:46:29 +08:00
|
|
|
llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators;
|
|
|
|
|
2007-01-24 04:11:08 +08:00
|
|
|
// While we still have something to read, read the declarations in the struct.
|
2007-10-10 01:33:22 +08:00
|
|
|
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
|
2007-01-23 12:38:16 +08:00
|
|
|
// Each iteration of this loop reads one struct-declaration.
|
|
|
|
|
2007-06-09 13:59:07 +08:00
|
|
|
// Check for extraneous top-level semicolon.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2007-06-09 13:49:55 +08:00
|
|
|
Diag(Tok, diag::ext_extra_struct_semi);
|
|
|
|
ConsumeToken();
|
|
|
|
continue;
|
|
|
|
}
|
2008-04-10 14:46:29 +08:00
|
|
|
|
|
|
|
// Parse all the comma separated declarators.
|
|
|
|
DeclSpec DS;
|
|
|
|
FieldDeclarators.clear();
|
2008-06-22 03:39:06 +08:00
|
|
|
if (!Tok.is(tok::at)) {
|
|
|
|
ParseStructDeclaration(DS, FieldDeclarators);
|
|
|
|
|
|
|
|
// Convert them all to fields.
|
|
|
|
for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) {
|
|
|
|
FieldDeclarator &FD = FieldDeclarators[i];
|
|
|
|
// Install the declarator into the current TagDecl.
|
|
|
|
DeclTy *Field = Actions.ActOnField(CurScope,
|
|
|
|
DS.getSourceRange().getBegin(),
|
|
|
|
FD.D, FD.BitfieldSize);
|
|
|
|
FieldDecls.push_back(Field);
|
|
|
|
}
|
|
|
|
} else { // Handle @defs
|
|
|
|
ConsumeToken();
|
|
|
|
if (!Tok.isObjCAtKeyword(tok::objc_defs)) {
|
|
|
|
Diag(Tok, diag::err_unexpected_at);
|
|
|
|
SkipUntil(tok::semi, true, true);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ConsumeToken();
|
|
|
|
ExpectAndConsume(tok::l_paren, diag::err_expected_lparen);
|
|
|
|
if (!Tok.is(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
SkipUntil(tok::semi, true, true);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
llvm::SmallVector<DeclTy*, 16> Fields;
|
|
|
|
Actions.ActOnDefs(CurScope, Tok.getLocation(), Tok.getIdentifierInfo(),
|
|
|
|
Fields);
|
|
|
|
FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end());
|
|
|
|
ConsumeToken();
|
|
|
|
ExpectAndConsume(tok::r_paren, diag::err_expected_rparen);
|
|
|
|
}
|
2007-06-09 13:59:07 +08:00
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2007-01-23 12:38:16 +08:00
|
|
|
ConsumeToken();
|
2007-10-10 01:33:22 +08:00
|
|
|
} else if (Tok.is(tok::r_brace)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::ext_expected_semi_decl_list);
|
2007-06-09 13:54:40 +08:00
|
|
|
break;
|
2007-01-23 12:38:16 +08:00
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_expected_semi_decl_list);
|
|
|
|
// Skip to end of block or statement
|
|
|
|
SkipUntil(tok::r_brace, true, true);
|
|
|
|
}
|
2006-08-14 06:21:02 +08:00
|
|
|
}
|
2007-01-23 12:38:16 +08:00
|
|
|
|
2007-10-30 05:38:07 +08:00
|
|
|
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
|
2007-01-23 12:38:16 +08:00
|
|
|
|
2007-06-09 11:39:29 +08:00
|
|
|
AttributeList *AttrList = 0;
|
2007-01-23 12:38:16 +08:00
|
|
|
// If attributes exist after struct contents, parse them.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::kw___attribute))
|
2008-10-04 00:42:10 +08:00
|
|
|
AttrList = ParseAttributes();
|
2008-10-03 10:03:53 +08:00
|
|
|
|
|
|
|
Actions.ActOnFields(CurScope,
|
|
|
|
RecordLoc,TagDecl,&FieldDecls[0],FieldDecls.size(),
|
|
|
|
LBraceLoc, RBraceLoc,
|
|
|
|
AttrList);
|
2006-08-13 09:16:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-13 08:12:11 +08:00
|
|
|
/// ParseEnumSpecifier
|
2006-08-13 09:16:23 +08:00
|
|
|
/// enum-specifier: [C99 6.7.2.2]
|
2006-08-13 08:12:11 +08:00
|
|
|
/// 'enum' identifier[opt] '{' enumerator-list '}'
|
2008-11-09 00:45:02 +08:00
|
|
|
///[C99/C++]'enum' identifier[opt] '{' enumerator-list ',' '}'
|
2006-08-15 12:50:22 +08:00
|
|
|
/// [GNU] 'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt]
|
|
|
|
/// '}' attributes[opt]
|
2006-08-13 08:12:11 +08:00
|
|
|
/// 'enum' identifier
|
2006-08-15 12:50:22 +08:00
|
|
|
/// [GNU] 'enum' attributes[opt] identifier
|
2008-11-09 00:45:02 +08:00
|
|
|
///
|
|
|
|
/// [C++] elaborated-type-specifier:
|
|
|
|
/// [C++] 'enum' '::'[opt] nested-name-specifier[opt] identifier
|
|
|
|
///
|
2007-01-25 15:29:02 +08:00
|
|
|
void Parser::ParseEnumSpecifier(DeclSpec &DS) {
|
2007-10-10 01:33:22 +08:00
|
|
|
assert(Tok.is(tok::kw_enum) && "Not an enum specifier");
|
2007-01-25 15:29:02 +08:00
|
|
|
SourceLocation StartLoc = ConsumeToken();
|
|
|
|
|
|
|
|
// Parse the tag portion of this.
|
2008-09-11 08:21:41 +08:00
|
|
|
|
|
|
|
AttributeList *Attr = 0;
|
|
|
|
// If attributes exist after tag, parse them.
|
|
|
|
if (Tok.is(tok::kw___attribute))
|
|
|
|
Attr = ParseAttributes();
|
2008-11-09 00:45:02 +08:00
|
|
|
|
|
|
|
CXXScopeSpec SS;
|
|
|
|
if (isTokenCXXScopeSpecifier()) {
|
|
|
|
ParseCXXScopeSpecifier(SS);
|
|
|
|
if (Tok.isNot(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
|
|
|
// Has no name and is not a definition.
|
|
|
|
// Skip the rest of this declarator, up until the comma or semicolon.
|
|
|
|
SkipUntil(tok::comma, true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-09-11 08:21:41 +08:00
|
|
|
|
|
|
|
// Must have either 'enum name' or 'enum {...}'.
|
|
|
|
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace)) {
|
|
|
|
Diag(Tok, diag::err_expected_ident_lbrace);
|
|
|
|
|
|
|
|
// Skip the rest of this declarator, up until the comma or semicolon.
|
|
|
|
SkipUntil(tok::comma, true);
|
2007-01-25 15:29:02 +08:00
|
|
|
return;
|
2008-09-11 08:21:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If an identifier is present, consume and remember it.
|
|
|
|
IdentifierInfo *Name = 0;
|
|
|
|
SourceLocation NameLoc;
|
|
|
|
if (Tok.is(tok::identifier)) {
|
|
|
|
Name = Tok.getIdentifierInfo();
|
|
|
|
NameLoc = ConsumeToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
// There are three options here. If we have 'enum foo;', then this is a
|
|
|
|
// forward declaration. If we have 'enum foo {...' then this is a
|
|
|
|
// definition. Otherwise we have something like 'enum foo xyz', a reference.
|
|
|
|
//
|
|
|
|
// This is needed to handle stuff like this right (C99 6.7.2.3p11):
|
|
|
|
// enum foo {..}; void bar() { enum foo; } <- new foo in bar.
|
|
|
|
// enum foo {..}; void bar() { enum foo x; } <- use of old foo.
|
|
|
|
//
|
|
|
|
Action::TagKind TK;
|
|
|
|
if (Tok.is(tok::l_brace))
|
|
|
|
TK = Action::TK_Definition;
|
|
|
|
else if (Tok.is(tok::semi))
|
|
|
|
TK = Action::TK_Declaration;
|
|
|
|
else
|
|
|
|
TK = Action::TK_Reference;
|
|
|
|
DeclTy *TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TK, StartLoc,
|
2008-11-09 00:45:02 +08:00
|
|
|
SS, Name, NameLoc, Attr);
|
2007-01-25 15:29:02 +08:00
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
2007-01-25 15:29:02 +08:00
|
|
|
ParseEnumBody(StartLoc, TagDecl);
|
|
|
|
|
|
|
|
// TODO: semantic analysis on the declspec for enums.
|
|
|
|
const char *PrevSpec = 0;
|
|
|
|
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, TagDecl))
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
|
2007-01-25 15:29:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseEnumBody - Parse a {} enclosed enumerator-list.
|
2006-08-13 08:12:11 +08:00
|
|
|
/// enumerator-list:
|
|
|
|
/// enumerator
|
2006-08-13 09:16:23 +08:00
|
|
|
/// enumerator-list ',' enumerator
|
2006-08-13 08:12:11 +08:00
|
|
|
/// enumerator:
|
|
|
|
/// enumeration-constant
|
2006-08-13 09:16:23 +08:00
|
|
|
/// enumeration-constant '=' constant-expression
|
2006-08-13 08:12:11 +08:00
|
|
|
/// enumeration-constant:
|
|
|
|
/// identifier
|
|
|
|
///
|
2007-01-25 15:29:02 +08:00
|
|
|
void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) {
|
|
|
|
SourceLocation LBraceLoc = ConsumeBrace();
|
2006-08-13 08:12:11 +08:00
|
|
|
|
2007-08-28 01:24:30 +08:00
|
|
|
// C does not allow an empty enumerator-list, C++ does [dcl.enum].
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::r_brace) && !getLang().CPlusPlus)
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::ext_empty_struct_union_enum) << "enum";
|
2006-08-13 08:12:11 +08:00
|
|
|
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::SmallVector<DeclTy*, 32> EnumConstantDecls;
|
2007-01-25 15:29:02 +08:00
|
|
|
|
2007-06-11 09:28:17 +08:00
|
|
|
DeclTy *LastEnumConstDecl = 0;
|
|
|
|
|
2007-01-25 15:29:02 +08:00
|
|
|
// Parse the enumerator-list.
|
2007-10-10 01:33:22 +08:00
|
|
|
while (Tok.is(tok::identifier)) {
|
2007-01-25 15:29:02 +08:00
|
|
|
IdentifierInfo *Ident = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation IdentLoc = ConsumeToken();
|
2006-08-14 09:30:12 +08:00
|
|
|
|
2007-01-25 15:29:02 +08:00
|
|
|
SourceLocation EqualLoc;
|
|
|
|
ExprTy *AssignedVal = 0;
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::equal)) {
|
2007-01-25 15:29:02 +08:00
|
|
|
EqualLoc = ConsumeToken();
|
|
|
|
ExprResult Res = ParseConstantExpression();
|
|
|
|
if (Res.isInvalid)
|
2007-04-28 03:13:15 +08:00
|
|
|
SkipUntil(tok::comma, tok::r_brace, true, true);
|
2007-01-25 15:29:02 +08:00
|
|
|
else
|
|
|
|
AssignedVal = Res.Val;
|
2006-08-13 08:12:11 +08:00
|
|
|
}
|
|
|
|
|
2007-01-25 15:29:02 +08:00
|
|
|
// Install the enumerator constant into EnumDecl.
|
2007-09-16 02:49:24 +08:00
|
|
|
DeclTy *EnumConstDecl = Actions.ActOnEnumConstant(CurScope, EnumDecl,
|
2007-06-11 09:28:17 +08:00
|
|
|
LastEnumConstDecl,
|
|
|
|
IdentLoc, Ident,
|
|
|
|
EqualLoc, AssignedVal);
|
|
|
|
EnumConstantDecls.push_back(EnumConstDecl);
|
|
|
|
LastEnumConstDecl = EnumConstDecl;
|
2007-01-25 15:29:02 +08:00
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-01-25 15:29:02 +08:00
|
|
|
break;
|
|
|
|
SourceLocation CommaLoc = ConsumeToken();
|
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.isNot(tok::identifier) && !getLang().C99)
|
2007-01-25 15:29:02 +08:00
|
|
|
Diag(CommaLoc, diag::ext_c99_enumerator_list_comma);
|
2006-08-13 08:12:11 +08:00
|
|
|
}
|
2006-08-14 06:16:42 +08:00
|
|
|
|
2007-01-25 15:29:02 +08:00
|
|
|
// Eat the }.
|
|
|
|
MatchRHSPunctuation(tok::r_brace, LBraceLoc);
|
|
|
|
|
2007-09-16 02:49:24 +08:00
|
|
|
Actions.ActOnEnumBody(StartLoc, EnumDecl, &EnumConstantDecls[0],
|
2007-01-25 15:29:02 +08:00
|
|
|
EnumConstantDecls.size());
|
2006-08-14 06:16:42 +08:00
|
|
|
|
2007-06-02 01:11:19 +08:00
|
|
|
DeclTy *AttrList = 0;
|
2007-01-25 15:29:02 +08:00
|
|
|
// If attributes exist after the identifier list, parse them.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::kw___attribute))
|
2007-06-02 01:11:19 +08:00
|
|
|
AttrList = ParseAttributes(); // FIXME: where do they do?
|
2006-08-13 08:12:11 +08:00
|
|
|
}
|
|
|
|
|
2008-02-12 07:15:56 +08:00
|
|
|
/// isTypeSpecifierQualifier - Return true if the current token could be the
|
|
|
|
/// start of a type-qualifier-list.
|
|
|
|
bool Parser::isTypeQualifier() const {
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default: return false;
|
|
|
|
// type-qualifier
|
|
|
|
case tok::kw_const:
|
|
|
|
case tok::kw_volatile:
|
|
|
|
case tok::kw_restrict:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-11 07:56:11 +08:00
|
|
|
/// isTypeSpecifierQualifier - Return true if the current token could be the
|
|
|
|
/// start of a specifier-qualifier-list.
|
2008-11-09 00:45:02 +08:00
|
|
|
bool Parser::isTypeSpecifierQualifier() {
|
|
|
|
// Annotate typenames and C++ scope specifiers.
|
|
|
|
TryAnnotateTypeOrScopeToken();
|
|
|
|
|
2006-08-11 07:56:11 +08:00
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default: return false;
|
2006-08-15 12:50:22 +08:00
|
|
|
// GNU attributes support.
|
|
|
|
case tok::kw___attribute:
|
2007-07-31 20:34:36 +08:00
|
|
|
// GNU typeof support.
|
|
|
|
case tok::kw_typeof:
|
|
|
|
|
2006-08-11 07:56:11 +08:00
|
|
|
// type-specifiers
|
|
|
|
case tok::kw_short:
|
|
|
|
case tok::kw_long:
|
|
|
|
case tok::kw_signed:
|
|
|
|
case tok::kw_unsigned:
|
|
|
|
case tok::kw__Complex:
|
|
|
|
case tok::kw__Imaginary:
|
|
|
|
case tok::kw_void:
|
|
|
|
case tok::kw_char:
|
2008-08-10 00:51:54 +08:00
|
|
|
case tok::kw_wchar_t:
|
2006-08-11 07:56:11 +08:00
|
|
|
case tok::kw_int:
|
|
|
|
case tok::kw_float:
|
|
|
|
case tok::kw_double:
|
2007-11-15 13:25:19 +08:00
|
|
|
case tok::kw_bool:
|
2006-08-11 07:56:11 +08:00
|
|
|
case tok::kw__Bool:
|
|
|
|
case tok::kw__Decimal32:
|
|
|
|
case tok::kw__Decimal64:
|
|
|
|
case tok::kw__Decimal128:
|
|
|
|
|
2008-04-14 02:59:07 +08:00
|
|
|
// struct-or-union-specifier (C99) or class-specifier (C++)
|
|
|
|
case tok::kw_class:
|
2006-08-11 07:56:11 +08:00
|
|
|
case tok::kw_struct:
|
|
|
|
case tok::kw_union:
|
|
|
|
// enum-specifier
|
|
|
|
case tok::kw_enum:
|
|
|
|
|
|
|
|
// type-qualifier
|
|
|
|
case tok::kw_const:
|
|
|
|
case tok::kw_volatile:
|
|
|
|
case tok::kw_restrict:
|
2008-11-09 00:45:02 +08:00
|
|
|
|
|
|
|
// typedef-name
|
|
|
|
case tok::annot_qualtypename:
|
2006-08-11 07:56:11 +08:00
|
|
|
return true;
|
2008-10-20 08:25:30 +08:00
|
|
|
|
|
|
|
// GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
|
|
|
|
case tok::less:
|
|
|
|
return getLang().ObjC1;
|
2006-08-11 07:56:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-07 01:24:14 +08:00
|
|
|
/// isDeclarationSpecifier() - Return true if the current token is part of a
|
|
|
|
/// declaration specifier.
|
2008-11-09 00:45:02 +08:00
|
|
|
bool Parser::isDeclarationSpecifier() {
|
|
|
|
// Annotate typenames and C++ scope specifiers.
|
|
|
|
TryAnnotateTypeOrScopeToken();
|
|
|
|
|
2006-08-07 01:24:14 +08:00
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default: return false;
|
|
|
|
// storage-class-specifier
|
|
|
|
case tok::kw_typedef:
|
|
|
|
case tok::kw_extern:
|
2007-12-18 08:16:02 +08:00
|
|
|
case tok::kw___private_extern__:
|
2006-08-07 01:24:14 +08:00
|
|
|
case tok::kw_static:
|
|
|
|
case tok::kw_auto:
|
|
|
|
case tok::kw_register:
|
|
|
|
case tok::kw___thread:
|
|
|
|
|
|
|
|
// type-specifiers
|
|
|
|
case tok::kw_short:
|
|
|
|
case tok::kw_long:
|
|
|
|
case tok::kw_signed:
|
|
|
|
case tok::kw_unsigned:
|
|
|
|
case tok::kw__Complex:
|
|
|
|
case tok::kw__Imaginary:
|
|
|
|
case tok::kw_void:
|
|
|
|
case tok::kw_char:
|
2008-08-10 00:51:54 +08:00
|
|
|
case tok::kw_wchar_t:
|
2006-08-07 01:24:14 +08:00
|
|
|
case tok::kw_int:
|
|
|
|
case tok::kw_float:
|
|
|
|
case tok::kw_double:
|
2007-11-15 13:25:19 +08:00
|
|
|
case tok::kw_bool:
|
2006-08-07 01:24:14 +08:00
|
|
|
case tok::kw__Bool:
|
|
|
|
case tok::kw__Decimal32:
|
|
|
|
case tok::kw__Decimal64:
|
|
|
|
case tok::kw__Decimal128:
|
|
|
|
|
2008-04-14 02:59:07 +08:00
|
|
|
// struct-or-union-specifier (C99) or class-specifier (C++)
|
|
|
|
case tok::kw_class:
|
2006-08-07 01:24:14 +08:00
|
|
|
case tok::kw_struct:
|
|
|
|
case tok::kw_union:
|
|
|
|
// enum-specifier
|
|
|
|
case tok::kw_enum:
|
2006-08-11 07:56:11 +08:00
|
|
|
|
2006-08-07 01:24:14 +08:00
|
|
|
// type-qualifier
|
|
|
|
case tok::kw_const:
|
|
|
|
case tok::kw_volatile:
|
|
|
|
case tok::kw_restrict:
|
2007-07-31 20:34:36 +08:00
|
|
|
|
2006-08-07 01:24:14 +08:00
|
|
|
// function-specifier
|
|
|
|
case tok::kw_inline:
|
2008-10-31 17:07:45 +08:00
|
|
|
case tok::kw_virtual:
|
|
|
|
case tok::kw_explicit:
|
2007-08-10 00:40:21 +08:00
|
|
|
|
2008-11-09 00:45:02 +08:00
|
|
|
// typedef-name
|
|
|
|
case tok::annot_qualtypename:
|
|
|
|
|
2007-08-10 01:01:07 +08:00
|
|
|
// GNU typeof support.
|
|
|
|
case tok::kw_typeof:
|
|
|
|
|
|
|
|
// GNU attributes.
|
2007-08-10 00:40:21 +08:00
|
|
|
case tok::kw___attribute:
|
2008-07-26 11:38:44 +08:00
|
|
|
return true;
|
2008-06-05 08:02:44 +08:00
|
|
|
|
2008-07-26 11:38:44 +08:00
|
|
|
// GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
|
2008-06-05 08:02:44 +08:00
|
|
|
case tok::less:
|
2008-07-26 11:38:44 +08:00
|
|
|
return getLang().ObjC1;
|
2006-08-07 01:24:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-04 12:39:53 +08:00
|
|
|
|
2006-07-31 13:13:43 +08:00
|
|
|
/// ParseTypeQualifierListOpt
|
|
|
|
/// type-qualifier-list: [C99 6.7.5]
|
|
|
|
/// type-qualifier
|
2006-08-15 12:50:22 +08:00
|
|
|
/// [GNU] attributes
|
2006-07-31 13:13:43 +08:00
|
|
|
/// type-qualifier-list type-qualifier
|
2006-08-15 12:50:22 +08:00
|
|
|
/// [GNU] type-qualifier-list attributes
|
2006-07-31 13:13:43 +08:00
|
|
|
///
|
2006-08-05 14:26:47 +08:00
|
|
|
void Parser::ParseTypeQualifierListOpt(DeclSpec &DS) {
|
2006-07-31 13:13:43 +08:00
|
|
|
while (1) {
|
2006-08-05 14:26:47 +08:00
|
|
|
int isInvalid = false;
|
|
|
|
const char *PrevSpec = 0;
|
2006-11-28 13:18:46 +08:00
|
|
|
SourceLocation Loc = Tok.getLocation();
|
2006-08-05 14:26:47 +08:00
|
|
|
|
2006-07-31 13:13:43 +08:00
|
|
|
switch (Tok.getKind()) {
|
2006-08-05 14:26:47 +08:00
|
|
|
default:
|
2006-08-15 12:50:22 +08:00
|
|
|
// If this is not a type-qualifier token, we're done reading type
|
|
|
|
// qualifiers. First verify that DeclSpec's are consistent.
|
2007-12-12 05:27:55 +08:00
|
|
|
DS.Finish(Diags, PP.getSourceManager(), getLang());
|
2006-08-05 14:26:47 +08:00
|
|
|
return;
|
2006-07-31 13:13:43 +08:00
|
|
|
case tok::kw_const:
|
2006-11-28 13:18:46 +08:00
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec,
|
|
|
|
getLang())*2;
|
2006-08-05 14:26:47 +08:00
|
|
|
break;
|
2006-07-31 13:13:43 +08:00
|
|
|
case tok::kw_volatile:
|
2006-11-28 13:18:46 +08:00
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
|
|
|
|
getLang())*2;
|
2006-08-05 14:26:47 +08:00
|
|
|
break;
|
2006-07-31 13:13:43 +08:00
|
|
|
case tok::kw_restrict:
|
2006-11-28 13:18:46 +08:00
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
|
|
|
|
getLang())*2;
|
2006-07-31 13:13:43 +08:00
|
|
|
break;
|
2006-08-15 12:50:22 +08:00
|
|
|
case tok::kw___attribute:
|
2007-06-10 07:38:17 +08:00
|
|
|
DS.AddAttributes(ParseAttributes());
|
2007-06-07 07:19:11 +08:00
|
|
|
continue; // do *not* consume the next token!
|
2006-07-31 13:13:43 +08:00
|
|
|
}
|
2006-08-05 14:26:47 +08:00
|
|
|
|
|
|
|
// If the specifier combination wasn't legal, issue a diagnostic.
|
|
|
|
if (isInvalid) {
|
|
|
|
assert(PrevSpec && "Method did not return previous specifier!");
|
2008-11-18 15:48:38 +08:00
|
|
|
// Pick between error or extwarn.
|
|
|
|
unsigned DiagID = isInvalid == 1 ? diag::err_invalid_decl_spec_combination
|
|
|
|
: diag::ext_duplicate_declspec;
|
|
|
|
Diag(Tok, DiagID) << PrevSpec;
|
2006-08-05 14:26:47 +08:00
|
|
|
}
|
|
|
|
ConsumeToken();
|
2006-07-31 13:13:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-07 08:58:14 +08:00
|
|
|
|
|
|
|
/// ParseDeclarator - Parse and verify a newly-initialized declarator.
|
|
|
|
///
|
|
|
|
void Parser::ParseDeclarator(Declarator &D) {
|
|
|
|
/// This implements the 'declarator' production in the C grammar, then checks
|
|
|
|
/// for well-formedness and issues diagnostics.
|
2008-11-22 03:14:01 +08:00
|
|
|
ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
|
2006-08-07 08:58:14 +08:00
|
|
|
}
|
|
|
|
|
2008-11-22 03:14:01 +08:00
|
|
|
/// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator
|
|
|
|
/// is parsed by the function passed to it. Pass null, and the direct-declarator
|
|
|
|
/// isn't parsed at all, making this function effectively parse the C++
|
2008-11-08 04:08:42 +08:00
|
|
|
/// ptr-operator production.
|
|
|
|
///
|
2006-08-07 08:19:33 +08:00
|
|
|
/// declarator: [C99 6.7.5]
|
|
|
|
/// pointer[opt] direct-declarator
|
2007-06-03 07:28:54 +08:00
|
|
|
/// [C++] '&' declarator [C++ 8p4, dcl.decl]
|
|
|
|
/// [GNU] '&' restrict[opt] attributes[opt] declarator
|
2006-08-07 08:19:33 +08:00
|
|
|
///
|
|
|
|
/// pointer: [C99 6.7.5]
|
|
|
|
/// '*' type-qualifier-list[opt]
|
|
|
|
/// '*' type-qualifier-list[opt] pointer
|
|
|
|
///
|
2008-11-08 04:08:42 +08:00
|
|
|
/// ptr-operator:
|
|
|
|
/// '*' cv-qualifier-seq[opt]
|
|
|
|
/// '&'
|
|
|
|
/// [GNU] '&' restrict[opt] attributes[opt]
|
|
|
|
/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] [TODO]
|
2008-11-22 03:14:01 +08:00
|
|
|
void Parser::ParseDeclaratorInternal(Declarator &D,
|
|
|
|
DirectDeclParseFunction DirectDeclParser) {
|
2007-05-27 18:15:43 +08:00
|
|
|
tok::TokenKind Kind = Tok.getKind();
|
|
|
|
|
2008-08-28 00:04:49 +08:00
|
|
|
// Not a pointer, C++ reference, or block.
|
|
|
|
if (Kind != tok::star && (Kind != tok::amp || !getLang().CPlusPlus) &&
|
2008-11-08 04:08:42 +08:00
|
|
|
(Kind != tok::caret || !getLang().Blocks)) {
|
2008-11-22 03:14:01 +08:00
|
|
|
if (DirectDeclParser)
|
|
|
|
(this->*DirectDeclParser)(D);
|
2008-11-08 04:08:42 +08:00
|
|
|
return;
|
|
|
|
}
|
2006-08-07 08:19:33 +08:00
|
|
|
|
2008-08-28 18:07:06 +08:00
|
|
|
// Otherwise, '*' -> pointer, '^' -> block, '&' -> reference.
|
2007-05-27 18:15:43 +08:00
|
|
|
SourceLocation Loc = ConsumeToken(); // Eat the * or &.
|
|
|
|
|
2008-08-28 18:07:06 +08:00
|
|
|
if (Kind == tok::star || (Kind == tok::caret && getLang().Blocks)) {
|
2008-02-21 09:32:26 +08:00
|
|
|
// Is a pointer.
|
2007-05-27 18:15:43 +08:00
|
|
|
DeclSpec DS;
|
2007-06-07 07:19:11 +08:00
|
|
|
|
2007-05-27 18:15:43 +08:00
|
|
|
ParseTypeQualifierListOpt(DS);
|
2006-08-07 08:19:33 +08:00
|
|
|
|
2007-05-27 18:15:43 +08:00
|
|
|
// Recursively parse the declarator.
|
2008-11-22 03:14:01 +08:00
|
|
|
ParseDeclaratorInternal(D, DirectDeclParser);
|
2008-08-28 00:04:49 +08:00
|
|
|
if (Kind == tok::star)
|
|
|
|
// Remember that we parsed a pointer type, and remember the type-quals.
|
|
|
|
D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc,
|
|
|
|
DS.TakeAttributes()));
|
|
|
|
else
|
|
|
|
// Remember that we parsed a Block type, and remember the type-quals.
|
|
|
|
D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(),
|
|
|
|
Loc));
|
2007-05-27 18:15:43 +08:00
|
|
|
} else {
|
|
|
|
// Is a reference
|
2007-06-03 07:28:54 +08:00
|
|
|
DeclSpec DS;
|
|
|
|
|
|
|
|
// C++ 8.3.2p1: cv-qualified references are ill-formed except when the
|
|
|
|
// cv-qualifiers are introduced through the use of a typedef or of a
|
|
|
|
// template type argument, in which case the cv-qualifiers are ignored.
|
|
|
|
//
|
|
|
|
// [GNU] Retricted references are allowed.
|
|
|
|
// [GNU] Attributes on references are allowed.
|
|
|
|
ParseTypeQualifierListOpt(DS);
|
|
|
|
|
|
|
|
if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
|
|
|
|
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
|
|
|
|
Diag(DS.getConstSpecLoc(),
|
2008-11-18 15:48:38 +08:00
|
|
|
diag::err_invalid_reference_qualifier_application) << "const";
|
2007-06-03 07:28:54 +08:00
|
|
|
if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
|
|
|
|
Diag(DS.getVolatileSpecLoc(),
|
2008-11-18 15:48:38 +08:00
|
|
|
diag::err_invalid_reference_qualifier_application) << "volatile";
|
2007-06-03 07:28:54 +08:00
|
|
|
}
|
2007-05-27 18:15:43 +08:00
|
|
|
|
|
|
|
// Recursively parse the declarator.
|
2008-11-22 03:14:01 +08:00
|
|
|
ParseDeclaratorInternal(D, DirectDeclParser);
|
2006-08-07 08:19:33 +08:00
|
|
|
|
2008-11-03 23:51:28 +08:00
|
|
|
if (D.getNumTypeObjects() > 0) {
|
|
|
|
// C++ [dcl.ref]p4: There shall be no references to references.
|
|
|
|
DeclaratorChunk& InnerChunk = D.getTypeObject(D.getNumTypeObjects() - 1);
|
|
|
|
if (InnerChunk.Kind == DeclaratorChunk::Reference) {
|
2008-11-19 15:37:42 +08:00
|
|
|
if (const IdentifierInfo *II = D.getIdentifier())
|
|
|
|
Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference)
|
|
|
|
<< II;
|
|
|
|
else
|
|
|
|
Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference)
|
|
|
|
<< "type name";
|
2008-11-03 23:51:28 +08:00
|
|
|
|
2008-11-22 03:14:01 +08:00
|
|
|
// Once we've complained about the reference-to-reference, we
|
2008-11-03 23:51:28 +08:00
|
|
|
// can go ahead and build the (technically ill-formed)
|
|
|
|
// declarator: reference collapsing will take care of it.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-27 18:15:43 +08:00
|
|
|
// Remember that we parsed a reference type. It doesn't have type-quals.
|
2008-02-21 09:32:26 +08:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc,
|
|
|
|
DS.TakeAttributes()));
|
2007-05-27 18:15:43 +08:00
|
|
|
}
|
|
|
|
}
|
2006-07-31 13:13:43 +08:00
|
|
|
|
|
|
|
/// ParseDirectDeclarator
|
|
|
|
/// direct-declarator: [C99 6.7.5]
|
2008-11-06 04:51:48 +08:00
|
|
|
/// [C99] identifier
|
2006-07-31 13:13:43 +08:00
|
|
|
/// '(' declarator ')'
|
|
|
|
/// [GNU] '(' attributes declarator ')'
|
2006-08-07 02:30:15 +08:00
|
|
|
/// [C90] direct-declarator '[' constant-expression[opt] ']'
|
|
|
|
/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']'
|
|
|
|
/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
|
|
|
|
/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
|
|
|
|
/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
|
2006-07-31 13:13:43 +08:00
|
|
|
/// direct-declarator '(' parameter-type-list ')'
|
|
|
|
/// direct-declarator '(' identifier-list[opt] ')'
|
|
|
|
/// [GNU] direct-declarator '(' parameter-forward-declarations
|
|
|
|
/// parameter-type-list[opt] ')'
|
2008-10-25 05:46:40 +08:00
|
|
|
/// [C++] direct-declarator '(' parameter-declaration-clause ')'
|
|
|
|
/// cv-qualifier-seq[opt] exception-specification[opt]
|
2008-10-31 17:07:45 +08:00
|
|
|
/// [C++] declarator-id
|
2008-11-06 04:51:48 +08:00
|
|
|
///
|
|
|
|
/// declarator-id: [C++ 8]
|
|
|
|
/// id-expression
|
|
|
|
/// '::'[opt] nested-name-specifier[opt] type-name
|
|
|
|
///
|
|
|
|
/// id-expression: [C++ 5.1]
|
|
|
|
/// unqualified-id
|
|
|
|
/// qualified-id [TODO]
|
|
|
|
///
|
|
|
|
/// unqualified-id: [C++ 5.1]
|
|
|
|
/// identifier
|
2008-11-09 00:45:02 +08:00
|
|
|
/// operator-function-id
|
2008-11-06 04:51:48 +08:00
|
|
|
/// conversion-function-id [TODO]
|
|
|
|
/// '~' class-name
|
|
|
|
/// template-id [TODO]
|
2008-11-08 06:02:30 +08:00
|
|
|
///
|
2006-08-07 01:24:14 +08:00
|
|
|
void Parser::ParseDirectDeclarator(Declarator &D) {
|
2008-11-09 00:45:02 +08:00
|
|
|
CXXScopeSpec &SS = D.getCXXScopeSpec();
|
|
|
|
DeclaratorScopeObj DeclScopeObj(*this, SS);
|
|
|
|
|
|
|
|
if (D.mayHaveIdentifier() && isTokenCXXScopeSpecifier()) {
|
|
|
|
ParseCXXScopeSpecifier(SS);
|
|
|
|
// Change the declaration context for name lookup, until this function is
|
|
|
|
// exited (and the declarator has been parsed).
|
|
|
|
DeclScopeObj.EnterDeclaratorScope();
|
|
|
|
}
|
|
|
|
|
2006-08-07 01:24:14 +08:00
|
|
|
// Parse the first direct-declarator seen.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) {
|
2006-08-07 01:24:14 +08:00
|
|
|
assert(Tok.getIdentifierInfo() && "Not an identifier?");
|
2008-11-06 04:51:48 +08:00
|
|
|
// Determine whether this identifier is a C++ constructor name or
|
|
|
|
// a normal identifier.
|
|
|
|
if (getLang().CPlusPlus &&
|
2008-11-08 20:02:25 +08:00
|
|
|
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope))
|
2008-11-18 06:58:34 +08:00
|
|
|
D.setConstructor(Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope),
|
2008-11-13 07:21:09 +08:00
|
|
|
Tok.getLocation());
|
2008-11-06 04:51:48 +08:00
|
|
|
else
|
|
|
|
D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
|
2006-08-07 01:24:14 +08:00
|
|
|
ConsumeToken();
|
2008-11-08 06:02:30 +08:00
|
|
|
} else if (getLang().CPlusPlus &&
|
|
|
|
Tok.is(tok::tilde) && D.mayHaveIdentifier()) {
|
2008-11-06 04:51:48 +08:00
|
|
|
// This should be a C++ destructor.
|
|
|
|
SourceLocation TildeLoc = ConsumeToken();
|
2008-11-08 06:02:30 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
|
|
|
if (TypeTy *Type = ParseClassName())
|
2008-11-18 06:58:34 +08:00
|
|
|
D.setDestructor(Type, TildeLoc);
|
2008-11-08 06:02:30 +08:00
|
|
|
else
|
|
|
|
D.SetIdentifier(0, TildeLoc);
|
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_expected_class_name);
|
|
|
|
D.SetIdentifier(0, TildeLoc);
|
|
|
|
}
|
2008-11-07 06:13:31 +08:00
|
|
|
} else if (Tok.is(tok::kw_operator)) {
|
|
|
|
SourceLocation OperatorLoc = Tok.getLocation();
|
|
|
|
|
|
|
|
// First try the name of an overloaded operator
|
Extend DeclarationName to support C++ overloaded operators, e.g.,
operator+, directly, using the same mechanism as all other special
names.
Removed the "special" identifiers for the overloaded operators from
the identifier table and IdentifierInfo data structure. IdentifierInfo
is back to representing only real identifiers.
Added a new Action, ActOnOperatorFunctionIdExpr, that builds an
expression from an parsed operator-function-id (e.g., "operator
+"). ActOnIdentifierExpr used to do this job, but
operator-function-ids are no longer represented by IdentifierInfo's.
Extended Declarator to store overloaded operator names.
Sema::GetNameForDeclarator now knows how to turn the operator
name into a DeclarationName for the overloaded operator.
Except for (perhaps) consolidating the functionality of
ActOnIdentifier, ActOnOperatorFunctionIdExpr, and
ActOnConversionFunctionExpr into a common routine that builds an
appropriate DeclRefExpr by looking up a DeclarationName, all of the
work on normalizing declaration names should be complete with this
commit.
llvm-svn: 59526
2008-11-18 22:39:36 +08:00
|
|
|
if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) {
|
|
|
|
D.setOverloadedOperator(Op, OperatorLoc);
|
2008-11-07 06:13:31 +08:00
|
|
|
} else {
|
2008-11-08 04:08:42 +08:00
|
|
|
// This must be a conversion function (C++ [class.conv.fct]).
|
|
|
|
if (TypeTy *ConvType = ParseConversionFunctionId()) {
|
2008-11-18 06:58:34 +08:00
|
|
|
D.setConversionFunction(ConvType, OperatorLoc);
|
2008-11-08 04:08:42 +08:00
|
|
|
}
|
2008-11-07 06:13:31 +08:00
|
|
|
}
|
2008-11-09 00:45:02 +08:00
|
|
|
} else if (Tok.is(tok::l_paren) && SS.isEmpty()) {
|
2006-08-07 01:24:14 +08:00
|
|
|
// direct-declarator: '(' declarator ')'
|
2006-08-15 12:50:22 +08:00
|
|
|
// direct-declarator: '(' attributes declarator ')'
|
2006-08-07 01:24:14 +08:00
|
|
|
// Example: 'char (*X)' or 'int (*XX)(void)'
|
|
|
|
ParseParenDeclarator(D);
|
2008-11-09 00:45:02 +08:00
|
|
|
} else if (D.mayOmitIdentifier() && SS.isEmpty()) {
|
2006-08-07 01:24:14 +08:00
|
|
|
// This could be something simple like "int" (in which case the declarator
|
|
|
|
// portion is empty), if an abstract-declarator is allowed.
|
|
|
|
D.SetIdentifier(0, Tok.getLocation());
|
|
|
|
} else {
|
2008-11-09 00:45:02 +08:00
|
|
|
if (getLang().CPlusPlus)
|
|
|
|
Diag(Tok, diag::err_expected_unqualified_id);
|
|
|
|
else
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident_lparen);
|
2006-08-07 05:55:29 +08:00
|
|
|
D.SetIdentifier(0, Tok.getLocation());
|
2008-11-11 14:13:16 +08:00
|
|
|
D.setInvalidType(true);
|
2006-08-07 01:24:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
assert(D.isPastIdentifier() &&
|
|
|
|
"Haven't past the location of the identifier yet?");
|
|
|
|
|
|
|
|
while (1) {
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
2008-10-07 01:10:33 +08:00
|
|
|
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
|
|
|
|
// In such a case, check if we actually have a function declarator; if it
|
|
|
|
// is not, the declarator has been fully parsed.
|
2008-10-20 10:05:46 +08:00
|
|
|
if (getLang().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) {
|
|
|
|
// When not in file scope, warn for ambiguous function declarators, just
|
|
|
|
// in case the author intended it as a variable definition.
|
|
|
|
bool warnIfAmbiguous = D.getContext() != Declarator::FileContext;
|
|
|
|
if (!isCXXFunctionDeclarator(warnIfAmbiguous))
|
|
|
|
break;
|
|
|
|
}
|
2008-04-06 13:45:57 +08:00
|
|
|
ParseFunctionDeclarator(ConsumeParen(), D);
|
2007-10-10 01:33:22 +08:00
|
|
|
} else if (Tok.is(tok::l_square)) {
|
2006-08-07 02:30:15 +08:00
|
|
|
ParseBracketDeclarator(D);
|
2006-08-07 01:24:14 +08:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-06 13:45:57 +08:00
|
|
|
/// ParseParenDeclarator - We parsed the declarator D up to a paren. This is
|
|
|
|
/// only called before the identifier, so these are most likely just grouping
|
|
|
|
/// parens for precedence. If we find that these are actually function
|
|
|
|
/// parameter parens in an abstract-declarator, we call ParseFunctionDeclarator.
|
|
|
|
///
|
|
|
|
/// direct-declarator:
|
|
|
|
/// '(' declarator ')'
|
|
|
|
/// [GNU] '(' attributes declarator ')'
|
2008-10-20 10:05:46 +08:00
|
|
|
/// direct-declarator '(' parameter-type-list ')'
|
|
|
|
/// direct-declarator '(' identifier-list[opt] ')'
|
|
|
|
/// [GNU] direct-declarator '(' parameter-forward-declarations
|
|
|
|
/// parameter-type-list[opt] ')'
|
2008-04-06 13:45:57 +08:00
|
|
|
///
|
|
|
|
void Parser::ParseParenDeclarator(Declarator &D) {
|
|
|
|
SourceLocation StartLoc = ConsumeParen();
|
|
|
|
assert(!D.isPastIdentifier() && "Should be called before passing identifier");
|
|
|
|
|
2008-10-20 10:05:46 +08:00
|
|
|
// Eat any attributes before we look at whether this is a grouping or function
|
|
|
|
// declarator paren. If this is a grouping paren, the attribute applies to
|
|
|
|
// the type being built up, for example:
|
|
|
|
// int (__attribute__(()) *x)(long y)
|
|
|
|
// If this ends up not being a grouping paren, the attribute applies to the
|
|
|
|
// first argument, for example:
|
|
|
|
// int (__attribute__(()) int x)
|
|
|
|
// In either case, we need to eat any attributes to be able to determine what
|
|
|
|
// sort of paren this is.
|
|
|
|
//
|
|
|
|
AttributeList *AttrList = 0;
|
|
|
|
bool RequiresArg = false;
|
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
AttrList = ParseAttributes();
|
|
|
|
|
|
|
|
// We require that the argument list (if this is a non-grouping paren) be
|
|
|
|
// present even if the attribute list was empty.
|
|
|
|
RequiresArg = true;
|
|
|
|
}
|
|
|
|
|
2008-04-06 13:45:57 +08:00
|
|
|
// If we haven't past the identifier yet (or where the identifier would be
|
|
|
|
// stored, if this is an abstract declarator), then this is probably just
|
|
|
|
// grouping parens. However, if this could be an abstract-declarator, then
|
|
|
|
// this could also be the start of function arguments (consider 'void()').
|
|
|
|
bool isGrouping;
|
|
|
|
|
|
|
|
if (!D.mayOmitIdentifier()) {
|
|
|
|
// If this can't be an abstract-declarator, this *must* be a grouping
|
|
|
|
// paren, because we haven't seen the identifier yet.
|
|
|
|
isGrouping = true;
|
|
|
|
} else if (Tok.is(tok::r_paren) || // 'int()' is a function.
|
2008-10-06 08:07:55 +08:00
|
|
|
(getLang().CPlusPlus && Tok.is(tok::ellipsis)) || // C++ int(...)
|
2008-04-06 13:45:57 +08:00
|
|
|
isDeclarationSpecifier()) { // 'int(int)' is a function.
|
|
|
|
// This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is
|
|
|
|
// considered to be a type, not a K&R identifier-list.
|
|
|
|
isGrouping = false;
|
|
|
|
} else {
|
|
|
|
// Otherwise, this is a grouping paren, e.g. 'int (*X)' or 'int(X)'.
|
|
|
|
isGrouping = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this is a grouping paren, handle:
|
|
|
|
// direct-declarator: '(' declarator ')'
|
|
|
|
// direct-declarator: '(' attributes declarator ')'
|
|
|
|
if (isGrouping) {
|
2008-10-07 18:21:57 +08:00
|
|
|
bool hadGroupingParens = D.hasGroupingParens();
|
2008-10-07 01:10:33 +08:00
|
|
|
D.setGroupingParens(true);
|
2008-10-20 10:05:46 +08:00
|
|
|
if (AttrList)
|
|
|
|
D.AddAttributes(AttrList);
|
2008-10-07 01:10:33 +08:00
|
|
|
|
2008-11-22 03:14:01 +08:00
|
|
|
ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
|
2008-04-06 13:45:57 +08:00
|
|
|
// Match the ')'.
|
|
|
|
MatchRHSPunctuation(tok::r_paren, StartLoc);
|
2008-10-07 18:21:57 +08:00
|
|
|
|
|
|
|
D.setGroupingParens(hadGroupingParens);
|
2008-04-06 13:45:57 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Okay, if this wasn't a grouping paren, it must be the start of a function
|
|
|
|
// argument list. Recognize that this declarator will never have an
|
2008-10-20 10:05:46 +08:00
|
|
|
// identifier (and remember where it would have been), then call into
|
|
|
|
// ParseFunctionDeclarator to handle of argument list.
|
2008-04-06 13:45:57 +08:00
|
|
|
D.SetIdentifier(0, Tok.getLocation());
|
|
|
|
|
2008-10-20 10:05:46 +08:00
|
|
|
ParseFunctionDeclarator(StartLoc, D, AttrList, RequiresArg);
|
2008-04-06 13:45:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseFunctionDeclarator - We are after the identifier and have parsed the
|
|
|
|
/// declarator D up to a paren, which indicates that we are parsing function
|
|
|
|
/// arguments.
|
2006-08-07 01:24:14 +08:00
|
|
|
///
|
2008-10-20 10:05:46 +08:00
|
|
|
/// If AttrList is non-null, then the caller parsed those arguments immediately
|
|
|
|
/// after the open paren - they should be considered to be the first argument of
|
|
|
|
/// a parameter. If RequiresArg is true, then the first argument of the
|
|
|
|
/// function is required to be present and required to not be an identifier
|
|
|
|
/// list.
|
|
|
|
///
|
2006-08-07 01:24:14 +08:00
|
|
|
/// This method also handles this portion of the grammar:
|
2006-07-31 13:13:43 +08:00
|
|
|
/// parameter-type-list: [C99 6.7.5]
|
|
|
|
/// parameter-list
|
|
|
|
/// parameter-list ',' '...'
|
|
|
|
///
|
|
|
|
/// parameter-list: [C99 6.7.5]
|
|
|
|
/// parameter-declaration
|
|
|
|
/// parameter-list ',' parameter-declaration
|
|
|
|
///
|
|
|
|
/// parameter-declaration: [C99 6.7.5]
|
|
|
|
/// declaration-specifiers declarator
|
2008-04-08 12:40:51 +08:00
|
|
|
/// [C++] declaration-specifiers declarator '=' assignment-expression
|
2006-08-15 12:50:22 +08:00
|
|
|
/// [GNU] declaration-specifiers declarator attributes
|
2006-07-31 13:13:43 +08:00
|
|
|
/// declaration-specifiers abstract-declarator[opt]
|
2008-04-10 10:22:51 +08:00
|
|
|
/// [C++] declaration-specifiers abstract-declarator[opt]
|
|
|
|
/// '=' assignment-expression
|
2006-08-15 12:50:22 +08:00
|
|
|
/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
|
2006-07-31 13:13:43 +08:00
|
|
|
///
|
2008-10-25 05:46:40 +08:00
|
|
|
/// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]"
|
|
|
|
/// and "exception-specification[opt]"(TODO).
|
|
|
|
///
|
2008-10-20 10:05:46 +08:00
|
|
|
void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
|
|
|
|
AttributeList *AttrList,
|
|
|
|
bool RequiresArg) {
|
2008-04-06 13:45:57 +08:00
|
|
|
// lparen is already consumed!
|
|
|
|
assert(D.isPastIdentifier() && "Should not call before identifier!");
|
2006-08-05 14:26:47 +08:00
|
|
|
|
2008-10-20 10:05:46 +08:00
|
|
|
// This parameter list may be empty.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::r_paren)) {
|
2008-10-20 10:05:46 +08:00
|
|
|
if (RequiresArg) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_argument_required_after_attribute);
|
2008-10-20 10:05:46 +08:00
|
|
|
delete AttrList;
|
|
|
|
}
|
2008-10-25 05:46:40 +08:00
|
|
|
|
|
|
|
ConsumeParen(); // Eat the closing ')'.
|
|
|
|
|
|
|
|
// cv-qualifier-seq[opt].
|
|
|
|
DeclSpec DS;
|
|
|
|
if (getLang().CPlusPlus) {
|
|
|
|
ParseTypeQualifierListOpt(DS);
|
|
|
|
// FIXME: Parse exception-specification[opt].
|
|
|
|
}
|
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
// Remember that we parsed a function type, and remember the attributes.
|
2006-08-07 01:24:14 +08:00
|
|
|
// int() -> no prototype, no '...'.
|
2008-10-25 05:46:40 +08:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/getLang().CPlusPlus,
|
2008-04-06 14:57:35 +08:00
|
|
|
/*variadic*/ false,
|
2008-10-25 05:46:40 +08:00
|
|
|
/*arglist*/ 0, 0,
|
|
|
|
DS.getTypeQualifiers(),
|
|
|
|
LParenLoc));
|
2008-04-06 14:57:35 +08:00
|
|
|
return;
|
2008-10-20 10:05:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Alternatively, this parameter list may be an identifier list form for a
|
|
|
|
// K&R-style function: void foo(a,b,c)
|
2008-10-25 05:46:40 +08:00
|
|
|
if (!getLang().CPlusPlus && Tok.is(tok::identifier) &&
|
2008-10-20 10:05:46 +08:00
|
|
|
// K&R identifier lists can't have typedefs as identifiers, per
|
|
|
|
// C99 6.7.5.3p11.
|
|
|
|
!Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) {
|
|
|
|
if (RequiresArg) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_argument_required_after_attribute);
|
2008-10-20 10:05:46 +08:00
|
|
|
delete AttrList;
|
|
|
|
}
|
|
|
|
|
2006-08-07 01:24:14 +08:00
|
|
|
// Identifier list. Note that '(' identifier-list ')' is only allowed for
|
|
|
|
// normal declarators, not for abstract-declarators.
|
2008-04-06 14:34:08 +08:00
|
|
|
return ParseFunctionDeclaratorIdentifierList(LParenLoc, D);
|
2008-04-06 14:57:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, a normal, non-empty parameter type list.
|
|
|
|
|
|
|
|
// Build up an array of information about the parsed arguments.
|
|
|
|
llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
|
2008-04-08 12:40:51 +08:00
|
|
|
|
|
|
|
// Enter function-declaration scope, limiting any declarators to the
|
|
|
|
// function prototype scope, including parameter declarators.
|
2008-05-10 07:39:43 +08:00
|
|
|
EnterScope(Scope::FnScope|Scope::DeclScope);
|
2008-04-06 14:57:35 +08:00
|
|
|
|
|
|
|
bool IsVariadic = false;
|
|
|
|
while (1) {
|
|
|
|
if (Tok.is(tok::ellipsis)) {
|
|
|
|
IsVariadic = true;
|
|
|
|
|
|
|
|
// Check to see if this is "void(...)" which is not allowed.
|
2008-10-06 08:07:55 +08:00
|
|
|
if (!getLang().CPlusPlus && ParamInfo.empty()) {
|
2008-04-06 14:57:35 +08:00
|
|
|
// Otherwise, parse parameter type list. If it starts with an
|
|
|
|
// ellipsis, diagnose the malformed function.
|
|
|
|
Diag(Tok, diag::err_ellipsis_first_arg);
|
|
|
|
IsVariadic = false; // Treat this like 'void()'.
|
|
|
|
}
|
|
|
|
|
|
|
|
ConsumeToken(); // Consume the ellipsis.
|
|
|
|
break;
|
|
|
|
}
|
2006-11-28 12:05:37 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
SourceLocation DSStart = Tok.getLocation();
|
2006-11-28 12:05:37 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
// Parse the declaration-specifiers.
|
|
|
|
DeclSpec DS;
|
2008-10-20 10:05:46 +08:00
|
|
|
|
|
|
|
// If the caller parsed attributes for the first argument, add them now.
|
|
|
|
if (AttrList) {
|
|
|
|
DS.AddAttributes(AttrList);
|
|
|
|
AttrList = 0; // Only apply the attributes to the first parameter.
|
|
|
|
}
|
2008-04-06 14:57:35 +08:00
|
|
|
ParseDeclarationSpecifiers(DS);
|
2006-08-07 01:24:14 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
// Parse the declarator. This is "PrototypeContext", because we must
|
|
|
|
// accept either 'declarator' or 'abstract-declarator' here.
|
|
|
|
Declarator ParmDecl(DS, Declarator::PrototypeContext);
|
|
|
|
ParseDeclarator(ParmDecl);
|
2006-08-07 01:24:14 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
// Parse GNU attributes, if present.
|
|
|
|
if (Tok.is(tok::kw___attribute))
|
|
|
|
ParmDecl.AddAttributes(ParseAttributes());
|
|
|
|
|
|
|
|
// Remember this parsed parameter in ParamInfo.
|
|
|
|
IdentifierInfo *ParmII = ParmDecl.getIdentifier();
|
|
|
|
|
|
|
|
// If no parameter was specified, verify that *something* was specified,
|
|
|
|
// otherwise we have a missing type and identifier.
|
|
|
|
if (DS.getParsedSpecifiers() == DeclSpec::PQ_None &&
|
|
|
|
ParmDecl.getIdentifier() == 0 && ParmDecl.getNumTypeObjects() == 0) {
|
|
|
|
// Completely missing, emit error.
|
|
|
|
Diag(DSStart, diag::err_missing_param);
|
|
|
|
} else {
|
|
|
|
// Otherwise, we have something. Add it and let semantic analysis try
|
|
|
|
// to grok it and add the result to the ParamInfo we are building.
|
2006-12-03 14:29:03 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
// Inform the actions module about the parameter declarator, so it gets
|
|
|
|
// added to the current scope.
|
2008-04-08 12:40:51 +08:00
|
|
|
DeclTy *Param = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
|
|
|
|
|
|
|
|
// Parse the default argument, if any. We parse the default
|
|
|
|
// arguments in all dialects; the semantic analysis in
|
|
|
|
// ActOnParamDefaultArgument will reject the default argument in
|
|
|
|
// C.
|
|
|
|
if (Tok.is(tok::equal)) {
|
|
|
|
SourceLocation EqualLoc = Tok.getLocation();
|
|
|
|
|
|
|
|
// Consume the '='.
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// Parse the default argument
|
|
|
|
ExprResult DefArgResult = ParseAssignmentExpression();
|
|
|
|
if (DefArgResult.isInvalid) {
|
|
|
|
SkipUntil(tok::comma, tok::r_paren, true, true);
|
|
|
|
} else {
|
|
|
|
// Inform the actions module about the default argument
|
|
|
|
Actions.ActOnParamDefaultArgument(Param, EqualLoc, DefArgResult.Val);
|
|
|
|
}
|
|
|
|
}
|
2006-08-07 01:24:14 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
|
2008-04-08 12:40:51 +08:00
|
|
|
ParmDecl.getIdentifierLoc(), Param));
|
2006-08-07 01:24:14 +08:00
|
|
|
}
|
2008-04-06 14:57:35 +08:00
|
|
|
|
|
|
|
// If the next token is a comma, consume it and keep reading arguments.
|
|
|
|
if (Tok.isNot(tok::comma)) break;
|
2006-08-07 01:24:14 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
// Consume the comma.
|
|
|
|
ConsumeToken();
|
2006-08-07 01:24:14 +08:00
|
|
|
}
|
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
// Leave prototype scope.
|
|
|
|
ExitScope();
|
|
|
|
|
2008-10-25 05:46:40 +08:00
|
|
|
// If we have the closing ')', eat it.
|
|
|
|
MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
|
|
|
|
|
|
|
// cv-qualifier-seq[opt].
|
|
|
|
DeclSpec DS;
|
|
|
|
if (getLang().CPlusPlus) {
|
|
|
|
ParseTypeQualifierListOpt(DS);
|
|
|
|
// FIXME: Parse exception-specification[opt].
|
|
|
|
}
|
|
|
|
|
2006-08-07 08:58:14 +08:00
|
|
|
// Remember that we parsed a function type, and remember the attributes.
|
2008-04-06 14:57:35 +08:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic,
|
|
|
|
&ParamInfo[0], ParamInfo.size(),
|
2008-10-25 05:46:40 +08:00
|
|
|
DS.getTypeQualifiers(),
|
2008-04-06 14:57:35 +08:00
|
|
|
LParenLoc));
|
2006-07-31 13:13:43 +08:00
|
|
|
}
|
2006-08-07 01:24:14 +08:00
|
|
|
|
2008-04-06 14:34:08 +08:00
|
|
|
/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator
|
|
|
|
/// we found a K&R-style identifier list instead of a type argument list. The
|
|
|
|
/// current token is known to be the first identifier in the list.
|
|
|
|
///
|
|
|
|
/// identifier-list: [C99 6.7.5]
|
|
|
|
/// identifier
|
|
|
|
/// identifier-list ',' identifier
|
|
|
|
///
|
|
|
|
void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
|
|
|
|
Declarator &D) {
|
|
|
|
// Build up an array of information about the parsed arguments.
|
|
|
|
llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
|
|
|
|
llvm::SmallSet<const IdentifierInfo*, 16> ParamsSoFar;
|
|
|
|
|
|
|
|
// If there was no identifier specified for the declarator, either we are in
|
|
|
|
// an abstract-declarator, or we are in a parameter declarator which was found
|
|
|
|
// to be abstract. In abstract-declarators, identifier lists are not valid:
|
|
|
|
// diagnose this.
|
|
|
|
if (!D.getIdentifier())
|
|
|
|
Diag(Tok, diag::ext_ident_list_in_param);
|
|
|
|
|
|
|
|
// Tok is known to be the first identifier in the list. Remember this
|
|
|
|
// identifier in ParamInfo.
|
2008-04-06 14:50:56 +08:00
|
|
|
ParamsSoFar.insert(Tok.getIdentifierInfo());
|
2008-04-06 14:34:08 +08:00
|
|
|
ParamInfo.push_back(DeclaratorChunk::ParamInfo(Tok.getIdentifierInfo(),
|
|
|
|
Tok.getLocation(), 0));
|
|
|
|
|
2008-04-06 14:39:19 +08:00
|
|
|
ConsumeToken(); // eat the first identifier.
|
2008-04-06 14:34:08 +08:00
|
|
|
|
|
|
|
while (Tok.is(tok::comma)) {
|
|
|
|
// Eat the comma.
|
|
|
|
ConsumeToken();
|
|
|
|
|
2008-04-06 14:39:19 +08:00
|
|
|
// If this isn't an identifier, report the error and skip until ')'.
|
2008-04-06 14:34:08 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
2008-04-06 14:39:19 +08:00
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
2008-04-06 14:34:08 +08:00
|
|
|
}
|
2008-04-06 14:47:48 +08:00
|
|
|
|
2008-04-06 14:34:08 +08:00
|
|
|
IdentifierInfo *ParmII = Tok.getIdentifierInfo();
|
2008-04-06 14:47:48 +08:00
|
|
|
|
|
|
|
// Reject 'typedef int y; int test(x, y)', but continue parsing.
|
|
|
|
if (Actions.isTypeName(*ParmII, CurScope))
|
2008-11-19 15:37:42 +08:00
|
|
|
Diag(Tok, diag::err_unexpected_typedef_ident) << ParmII;
|
2008-04-06 14:34:08 +08:00
|
|
|
|
|
|
|
// Verify that the argument identifier has not already been mentioned.
|
|
|
|
if (!ParamsSoFar.insert(ParmII)) {
|
2008-11-19 15:37:42 +08:00
|
|
|
Diag(Tok, diag::err_param_redefinition) << ParmII;
|
2008-04-06 14:39:19 +08:00
|
|
|
} else {
|
|
|
|
// Remember this identifier in ParamInfo.
|
2008-04-06 14:34:08 +08:00
|
|
|
ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
|
|
|
|
Tok.getLocation(), 0));
|
2008-04-06 14:39:19 +08:00
|
|
|
}
|
2008-04-06 14:34:08 +08:00
|
|
|
|
|
|
|
// Eat the identifier.
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
|
2008-04-06 14:39:19 +08:00
|
|
|
// Remember that we parsed a function type, and remember the attributes. This
|
|
|
|
// function type is always a K&R style function type, which is not varargs and
|
|
|
|
// has no prototype.
|
|
|
|
D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false,
|
|
|
|
&ParamInfo[0], ParamInfo.size(),
|
2008-10-25 05:46:40 +08:00
|
|
|
/*TypeQuals*/0, LParenLoc));
|
2008-04-06 14:34:08 +08:00
|
|
|
|
|
|
|
// If we have the closing ')', eat it and we're done.
|
2008-04-06 14:39:19 +08:00
|
|
|
MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2008-04-06 14:34:08 +08:00
|
|
|
}
|
2008-04-06 13:45:57 +08:00
|
|
|
|
2006-08-07 02:30:15 +08:00
|
|
|
/// [C90] direct-declarator '[' constant-expression[opt] ']'
|
|
|
|
/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']'
|
|
|
|
/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
|
|
|
|
/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
|
|
|
|
/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
|
|
|
|
void Parser::ParseBracketDeclarator(Declarator &D) {
|
2006-10-16 14:12:55 +08:00
|
|
|
SourceLocation StartLoc = ConsumeBracket();
|
2006-08-07 02:30:15 +08:00
|
|
|
|
|
|
|
// If valid, this location is the position where we read the 'static' keyword.
|
|
|
|
SourceLocation StaticLoc;
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::kw_static))
|
2006-10-16 14:06:51 +08:00
|
|
|
StaticLoc = ConsumeToken();
|
2006-08-07 02:30:15 +08:00
|
|
|
|
|
|
|
// If there is a type-qualifier-list, read it now.
|
|
|
|
DeclSpec DS;
|
|
|
|
ParseTypeQualifierListOpt(DS);
|
|
|
|
|
|
|
|
// If we haven't already read 'static', check to see if there is one after the
|
|
|
|
// type-qualifier-list.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (!StaticLoc.isValid() && Tok.is(tok::kw_static))
|
2006-10-16 14:06:51 +08:00
|
|
|
StaticLoc = ConsumeToken();
|
2006-08-07 02:30:15 +08:00
|
|
|
|
|
|
|
// Handle "direct-declarator [ type-qual-list[opt] * ]".
|
|
|
|
bool isStar = false;
|
2006-08-13 02:40:58 +08:00
|
|
|
ExprResult NumElements(false);
|
2008-04-06 13:26:30 +08:00
|
|
|
|
|
|
|
// Handle the case where we have '[*]' as the array size. However, a leading
|
|
|
|
// star could be the start of an expression, for example 'X[*p + 4]'. Verify
|
|
|
|
// the the token after the star is a ']'. Since stars in arrays are
|
|
|
|
// infrequent, use of lookahead is not costly here.
|
|
|
|
if (Tok.is(tok::star) && GetLookAheadToken(1).is(tok::r_square)) {
|
2008-04-06 13:27:21 +08:00
|
|
|
ConsumeToken(); // Eat the '*'.
|
2006-08-07 03:14:46 +08:00
|
|
|
|
2008-04-06 13:26:30 +08:00
|
|
|
if (StaticLoc.isValid())
|
|
|
|
Diag(StaticLoc, diag::err_unspecified_vla_size_with_static);
|
|
|
|
StaticLoc = SourceLocation(); // Drop the static.
|
|
|
|
isStar = true;
|
2007-10-10 01:33:22 +08:00
|
|
|
} else if (Tok.isNot(tok::r_square)) {
|
2006-08-07 02:30:15 +08:00
|
|
|
// Parse the assignment-expression now.
|
2006-08-13 02:40:58 +08:00
|
|
|
NumElements = ParseAssignmentExpression();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there was an error parsing the assignment-expression, recover.
|
|
|
|
if (NumElements.isInvalid) {
|
|
|
|
// If the expression was invalid, skip it.
|
|
|
|
SkipUntil(tok::r_square);
|
|
|
|
return;
|
2006-08-07 02:30:15 +08:00
|
|
|
}
|
|
|
|
|
2006-08-15 12:55:54 +08:00
|
|
|
MatchRHSPunctuation(tok::r_square, StartLoc);
|
2006-08-13 02:25:42 +08:00
|
|
|
|
2006-08-07 02:30:15 +08:00
|
|
|
// If C99 isn't enabled, emit an ext-warn if the arg list wasn't empty and if
|
|
|
|
// it was not a constant expression.
|
|
|
|
if (!getLang().C99) {
|
|
|
|
// TODO: check C90 array constant exprness.
|
2006-08-14 03:58:17 +08:00
|
|
|
if (isStar || StaticLoc.isValid() ||
|
|
|
|
0/*TODO: NumElts is not a C90 constantexpr */)
|
2006-08-07 02:33:32 +08:00
|
|
|
Diag(StartLoc, diag::ext_c99_array_usage);
|
2006-08-07 02:30:15 +08:00
|
|
|
}
|
2007-06-03 07:28:54 +08:00
|
|
|
|
2006-08-07 08:19:33 +08:00
|
|
|
// Remember that we parsed a pointer type, and remember the type-quals.
|
2006-12-02 14:43:02 +08:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
|
|
|
|
StaticLoc.isValid(), isStar,
|
|
|
|
NumElements.Val, StartLoc));
|
2006-08-07 02:30:15 +08:00
|
|
|
}
|
|
|
|
|
2008-09-05 19:26:19 +08:00
|
|
|
/// [GNU] typeof-specifier:
|
|
|
|
/// typeof ( expressions )
|
|
|
|
/// typeof ( type-name )
|
|
|
|
/// [GNU/C++] typeof unary-expression
|
2007-07-31 20:34:36 +08:00
|
|
|
///
|
|
|
|
void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
|
2007-10-10 01:33:22 +08:00
|
|
|
assert(Tok.is(tok::kw_typeof) && "Not a typeof specifier");
|
2007-08-02 10:53:48 +08:00
|
|
|
const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo();
|
2007-07-31 20:34:36 +08:00
|
|
|
SourceLocation StartLoc = ConsumeToken();
|
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
2008-09-05 19:26:19 +08:00
|
|
|
if (!getLang().CPlusPlus) {
|
2008-11-19 15:37:42 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen_after) << BuiltinII;
|
2008-09-05 19:26:19 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ExprResult Result = ParseCastExpression(true/*isUnaryExpression*/);
|
|
|
|
if (Result.isInvalid)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const char *PrevSpec = 0;
|
|
|
|
// Check for duplicate type specifiers.
|
|
|
|
if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec,
|
|
|
|
Result.Val))
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
|
2008-09-05 19:26:19 +08:00
|
|
|
|
|
|
|
// FIXME: Not accurate, the range gets one token more than it should.
|
|
|
|
DS.SetRangeEnd(Tok.getLocation());
|
2007-08-02 10:53:48 +08:00
|
|
|
return;
|
2007-07-31 20:34:36 +08:00
|
|
|
}
|
2008-09-05 19:26:19 +08:00
|
|
|
|
2007-07-31 20:34:36 +08:00
|
|
|
SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
|
|
|
|
|
2008-10-06 03:56:22 +08:00
|
|
|
if (isTypeIdInParens()) {
|
2007-07-31 20:34:36 +08:00
|
|
|
TypeTy *Ty = ParseTypeName();
|
|
|
|
|
2007-08-01 07:56:32 +08:00
|
|
|
assert(Ty && "Parser::ParseTypeofSpecifier(): missing type");
|
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2007-08-01 07:56:32 +08:00
|
|
|
MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2007-08-02 10:53:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
RParenLoc = ConsumeParen();
|
|
|
|
const char *PrevSpec = 0;
|
|
|
|
// Check for duplicate type specifiers (e.g. "int typeof(int)").
|
|
|
|
if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec, Ty))
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
|
2007-07-31 20:34:36 +08:00
|
|
|
} else { // we have an expression.
|
|
|
|
ExprResult Result = ParseExpression();
|
2007-08-01 07:56:32 +08:00
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Result.isInvalid || Tok.isNot(tok::r_paren)) {
|
2007-08-01 07:56:32 +08:00
|
|
|
MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2007-08-02 10:53:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
RParenLoc = ConsumeParen();
|
|
|
|
const char *PrevSpec = 0;
|
|
|
|
// Check for duplicate type specifiers (e.g. "int typeof(int)").
|
|
|
|
if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec,
|
|
|
|
Result.Val))
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
|
2007-07-31 20:34:36 +08:00
|
|
|
}
|
2008-08-16 18:21:33 +08:00
|
|
|
DS.SetRangeEnd(RParenLoc);
|
2007-07-31 20:34:36 +08:00
|
|
|
}
|
|
|
|
|
2008-05-10 07:39:43 +08:00
|
|
|
|