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"
|
2009-01-29 13:15:15 +08:00
|
|
|
#include "clang/Parse/ParseDiagnostic.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++.
|
2009-05-30 02:02:33 +08:00
|
|
|
Action::TypeResult Parser::ParseTypeName(SourceRange *Range) {
|
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);
|
2009-05-30 02:02:33 +08:00
|
|
|
|
2006-08-11 07:56:11 +08:00
|
|
|
// Parse the abstract-declarator, if present.
|
|
|
|
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
|
|
|
|
ParseDeclarator(DeclaratorInfo);
|
2009-05-30 02:02:33 +08:00
|
|
|
if (Range)
|
|
|
|
*Range = DeclaratorInfo.getSourceRange();
|
|
|
|
|
2009-04-25 16:06:05 +08:00
|
|
|
if (DeclaratorInfo.isInvalidType())
|
2009-02-19 01:45:20 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return Actions.ActOnTypeName(CurScope, DeclaratorInfo);
|
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.
|
|
|
|
|
2009-02-10 02:23:29 +08:00
|
|
|
AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
|
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) ))
|
2008-11-26 06:21:31 +08:00
|
|
|
ExprVector ArgExprs(Actions);
|
2007-06-02 01:11:19 +08:00
|
|
|
bool ArgExprsOk = true;
|
|
|
|
|
|
|
|
// now parse the non-empty comma separated list of expressions
|
|
|
|
while (1) {
|
2008-12-12 05:36:32 +08:00
|
|
|
OwningExprResult ArgExpr(ParseAssignmentExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (ArgExpr.isInvalid()) {
|
2007-06-02 01:11:19 +08:00
|
|
|
ArgExprsOk = false;
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
break;
|
|
|
|
} else {
|
2008-12-10 08:02:53 +08:00
|
|
|
ArgExprs.push_back(ArgExpr.release());
|
2007-06-02 01:11:19 +08:00
|
|
|
}
|
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,
|
2008-11-26 06:21:31 +08:00
|
|
|
ParmLoc, ArgExprs.take(), ArgExprs.size(), CurrAttr);
|
2007-06-02 01:11:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else { // not an identifier
|
2009-06-26 14:32:41 +08:00
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::r_paren:
|
2007-06-02 01:11:19 +08:00
|
|
|
// parse a possibly empty comma separated list of expressions
|
|
|
|
// __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);
|
2009-06-26 14:32:41 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_char:
|
|
|
|
case tok::kw_wchar_t:
|
2009-07-14 14:30:34 +08:00
|
|
|
case tok::kw_char16_t:
|
|
|
|
case tok::kw_char32_t:
|
2009-06-26 14:32:41 +08:00
|
|
|
case tok::kw_bool:
|
|
|
|
case tok::kw_short:
|
|
|
|
case tok::kw_int:
|
|
|
|
case tok::kw_long:
|
|
|
|
case tok::kw_signed:
|
|
|
|
case tok::kw_unsigned:
|
|
|
|
case tok::kw_float:
|
|
|
|
case tok::kw_double:
|
|
|
|
case tok::kw_void:
|
|
|
|
case tok::kw_typeof:
|
|
|
|
// If it's a builtin type name, eat it and expect a rparen
|
|
|
|
// __attribute__(( vec_type_hint(char) ))
|
|
|
|
ConsumeToken();
|
|
|
|
CurrAttr = new AttributeList(AttrName, AttrNameLoc,
|
|
|
|
0, SourceLocation(), 0, 0, CurrAttr);
|
|
|
|
if (Tok.is(tok::r_paren))
|
|
|
|
ConsumeParen();
|
|
|
|
break;
|
|
|
|
default:
|
2007-06-02 01:11:19 +08:00
|
|
|
// __attribute__(( aligned(16) ))
|
2008-11-26 06:21:31 +08:00
|
|
|
ExprVector ArgExprs(Actions);
|
2007-06-02 01:11:19 +08:00
|
|
|
bool ArgExprsOk = true;
|
|
|
|
|
|
|
|
// now parse the list of expressions
|
|
|
|
while (1) {
|
2008-12-12 05:36:32 +08:00
|
|
|
OwningExprResult ArgExpr(ParseAssignmentExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (ArgExpr.isInvalid()) {
|
2007-06-02 01:11:19 +08:00
|
|
|
ArgExprsOk = false;
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
break;
|
|
|
|
} else {
|
2008-12-10 08:02:53 +08:00
|
|
|
ArgExprs.push_back(ArgExpr.release());
|
2007-06-02 01:11:19 +08:00
|
|
|
}
|
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
|
2008-11-26 06:21:31 +08:00
|
|
|
CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
|
|
|
|
SourceLocation(), ArgExprs.take(), ArgExprs.size(),
|
2007-06-09 11:39:29 +08:00
|
|
|
CurrAttr);
|
2007-06-02 01:11:19 +08:00
|
|
|
}
|
2009-06-26 14:32:41 +08:00
|
|
|
break;
|
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);
|
2009-02-10 02:23:29 +08:00
|
|
|
SourceLocation Loc = Tok.getLocation();;
|
|
|
|
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
|
|
|
|
SkipUntil(tok::r_paren, false);
|
|
|
|
}
|
|
|
|
if (EndLoc)
|
|
|
|
*EndLoc = Loc;
|
2007-06-02 01:11:19 +08:00
|
|
|
}
|
|
|
|
return CurrAttr;
|
2006-08-15 12:10:46 +08:00
|
|
|
}
|
|
|
|
|
2009-06-08 15:21:15 +08:00
|
|
|
/// ParseMicrosoftDeclSpec - Parse an __declspec construct
|
|
|
|
///
|
|
|
|
/// [MS] decl-specifier:
|
|
|
|
/// __declspec ( extended-decl-modifier-seq )
|
|
|
|
///
|
|
|
|
/// [MS] extended-decl-modifier-seq:
|
|
|
|
/// extended-decl-modifier[opt]
|
|
|
|
/// extended-decl-modifier extended-decl-modifier-seq
|
|
|
|
|
2009-06-09 07:27:34 +08:00
|
|
|
AttributeList* Parser::ParseMicrosoftDeclSpec(AttributeList *CurrAttr) {
|
2008-12-25 04:59:21 +08:00
|
|
|
assert(Tok.is(tok::kw___declspec) && "Not a declspec!");
|
2009-06-08 15:21:15 +08:00
|
|
|
|
2008-12-25 04:59:21 +08:00
|
|
|
ConsumeToken();
|
2009-06-08 15:21:15 +08:00
|
|
|
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
|
|
|
|
"declspec")) {
|
|
|
|
SkipUntil(tok::r_paren, true); // skip until ) or ;
|
|
|
|
return CurrAttr;
|
|
|
|
}
|
2009-06-09 07:27:34 +08:00
|
|
|
while (Tok.getIdentifierInfo()) {
|
2009-06-08 15:21:15 +08:00
|
|
|
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation AttrNameLoc = ConsumeToken();
|
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
ConsumeParen();
|
|
|
|
// FIXME: This doesn't parse __declspec(property(get=get_func_name))
|
|
|
|
// correctly.
|
|
|
|
OwningExprResult ArgExpr(ParseAssignmentExpression());
|
|
|
|
if (!ArgExpr.isInvalid()) {
|
|
|
|
ExprTy* ExprList = ArgExpr.take();
|
|
|
|
CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
|
|
|
|
SourceLocation(), &ExprList, 1,
|
|
|
|
CurrAttr, true);
|
|
|
|
}
|
|
|
|
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
|
|
|
|
SkipUntil(tok::r_paren, false);
|
|
|
|
} else {
|
|
|
|
CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, SourceLocation(),
|
|
|
|
0, 0, CurrAttr, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
|
|
|
|
SkipUntil(tok::r_paren, false);
|
2009-06-09 07:27:34 +08:00
|
|
|
return CurrAttr;
|
|
|
|
}
|
|
|
|
|
|
|
|
AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) {
|
|
|
|
// Treat these like attributes
|
|
|
|
// FIXME: Allow Sema to distinguish between these and real attributes!
|
|
|
|
while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) ||
|
|
|
|
Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___ptr64) ||
|
|
|
|
Tok.is(tok::kw___w64)) {
|
|
|
|
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation AttrNameLoc = ConsumeToken();
|
|
|
|
if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64))
|
|
|
|
// FIXME: Support these properly!
|
|
|
|
continue;
|
|
|
|
CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
|
|
|
|
SourceLocation(), 0, 0, CurrAttr, true);
|
|
|
|
}
|
|
|
|
return CurrAttr;
|
2008-12-25 04:59:21 +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.
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
/// 'Context' should be a Declarator::TheContext value. This returns the
|
|
|
|
/// location of the semicolon in DeclEnd.
|
2007-08-25 14:57:03 +08:00
|
|
|
///
|
|
|
|
/// declaration: [C99 6.7]
|
|
|
|
/// block-declaration ->
|
|
|
|
/// simple-declaration
|
|
|
|
/// others [FIXME]
|
2008-12-02 07:54:00 +08:00
|
|
|
/// [C++] template-declaration
|
2007-08-25 14:57:03 +08:00
|
|
|
/// [C++] namespace-definition
|
2008-12-30 11:27:21 +08:00
|
|
|
/// [C++] using-directive
|
2009-06-23 07:06:13 +08:00
|
|
|
/// [C++] using-declaration
|
2009-03-25 06:27:57 +08:00
|
|
|
/// [C++0x] static_assert-declaration
|
2007-08-25 14:57:03 +08:00
|
|
|
/// others... [FIXME]
|
|
|
|
///
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
|
|
|
|
SourceLocation &DeclEnd) {
|
2009-03-30 00:50:03 +08:00
|
|
|
DeclPtrTy SingleDecl;
|
2007-08-25 14:57:03 +08:00
|
|
|
switch (Tok.getKind()) {
|
2008-12-02 07:54:00 +08:00
|
|
|
case tok::kw_template:
|
2009-05-13 05:31:51 +08:00
|
|
|
case tok::kw_export:
|
2009-05-13 07:25:50 +08:00
|
|
|
SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd);
|
2009-03-30 00:50:03 +08:00
|
|
|
break;
|
2007-08-25 14:57:03 +08:00
|
|
|
case tok::kw_namespace:
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
SingleDecl = ParseNamespace(Context, DeclEnd);
|
2009-03-30 00:50:03 +08:00
|
|
|
break;
|
2008-12-30 11:27:21 +08:00
|
|
|
case tok::kw_using:
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd);
|
2009-03-30 00:50:03 +08:00
|
|
|
break;
|
2009-03-12 00:27:10 +08:00
|
|
|
case tok::kw_static_assert:
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
|
2009-03-30 00:50:03 +08:00
|
|
|
break;
|
2007-08-25 14:57:03 +08:00
|
|
|
default:
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
return ParseSimpleDeclaration(Context, DeclEnd);
|
2007-08-25 14:57:03 +08:00
|
|
|
}
|
2009-03-30 00:50:03 +08:00
|
|
|
|
|
|
|
// This routine returns a DeclGroup, if the thing we parsed only contains a
|
|
|
|
// single decl, convert it now.
|
|
|
|
return Actions.ConvertDeclToDeclGroup(SingleDecl);
|
2007-08-25 14:57:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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]
|
2009-03-30 01:27:48 +08:00
|
|
|
///
|
|
|
|
/// If RequireSemi is false, this does not check for a ';' at the end of the
|
|
|
|
/// declaration.
|
|
|
|
Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
SourceLocation &DeclEnd,
|
2009-03-30 01:27:48 +08:00
|
|
|
bool RequireSemi) {
|
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();
|
2009-03-30 00:50:03 +08:00
|
|
|
DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
|
|
|
|
return Actions.ConvertDeclToDeclGroup(TheDecl);
|
2006-08-14 03:58:17 +08:00
|
|
|
}
|
|
|
|
|
2006-08-10 13:19:57 +08:00
|
|
|
Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context);
|
|
|
|
ParseDeclarator(DeclaratorInfo);
|
|
|
|
|
2009-03-30 01:18:04 +08:00
|
|
|
DeclGroupPtrTy DG =
|
|
|
|
ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
|
2009-03-30 01:27:48 +08:00
|
|
|
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
DeclEnd = Tok.getLocation();
|
|
|
|
|
2009-03-30 01:27:48 +08:00
|
|
|
// If the client wants to check what comes after the declaration, just return
|
|
|
|
// immediately without checking anything!
|
|
|
|
if (!RequireSemi) return DG;
|
2009-03-30 01:18:04 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::semi)) {
|
|
|
|
ConsumeToken();
|
|
|
|
return DG;
|
|
|
|
}
|
|
|
|
|
2009-07-31 10:20:35 +08:00
|
|
|
Diag(Tok, diag::err_expected_semi_declaration);
|
2009-03-30 01:18:04 +08:00
|
|
|
// Skip to end of block or statement
|
|
|
|
SkipUntil(tok::r_brace, true, true);
|
|
|
|
if (Tok.is(tok::semi))
|
|
|
|
ConsumeToken();
|
|
|
|
return DG;
|
2006-08-10 13:19:57 +08:00
|
|
|
}
|
|
|
|
|
2009-05-13 05:31:51 +08:00
|
|
|
/// \brief Parse 'declaration' after parsing 'declaration-specifiers
|
|
|
|
/// declarator'. This method parses the remainder of the declaration
|
|
|
|
/// (including any attributes or initializer, among other things) and
|
|
|
|
/// finalizes the declaration.
|
2006-08-14 08:15:20 +08:00
|
|
|
///
|
|
|
|
/// 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 ')'
|
2009-03-25 06:27:57 +08:00
|
|
|
/// [C++0x] '=' 'default' [TODO]
|
|
|
|
/// [C++0x] '=' 'delete'
|
|
|
|
///
|
|
|
|
/// According to the standard grammar, =default and =delete are function
|
|
|
|
/// definitions, but that definitely doesn't fit with the parser here.
|
2006-08-14 08:15:20 +08:00
|
|
|
///
|
2009-06-24 07:11:28 +08:00
|
|
|
Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D,
|
|
|
|
const ParsedTemplateInfo &TemplateInfo) {
|
2009-05-13 05:31:51 +08:00
|
|
|
// If a simple-asm-expr is present, parse it.
|
|
|
|
if (Tok.is(tok::kw_asm)) {
|
|
|
|
SourceLocation Loc;
|
|
|
|
OwningExprResult AsmLabel(ParseSimpleAsm(&Loc));
|
|
|
|
if (AsmLabel.isInvalid()) {
|
|
|
|
SkipUntil(tok::semi, true, true);
|
|
|
|
return DeclPtrTy();
|
|
|
|
}
|
|
|
|
|
|
|
|
D.setAsmLabel(AsmLabel.release());
|
|
|
|
D.SetRangeEnd(Loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If attributes are present, parse them.
|
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
SourceLocation Loc;
|
|
|
|
AttributeList *AttrList = ParseAttributes(&Loc);
|
|
|
|
D.AddAttributes(AttrList, Loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Inform the current actions module that we just parsed this declarator.
|
2009-06-24 07:11:28 +08:00
|
|
|
DeclPtrTy ThisDecl = TemplateInfo.TemplateParams?
|
|
|
|
Actions.ActOnTemplateDeclarator(CurScope,
|
|
|
|
Action::MultiTemplateParamsArg(Actions,
|
|
|
|
TemplateInfo.TemplateParams->data(),
|
|
|
|
TemplateInfo.TemplateParams->size()),
|
|
|
|
D)
|
|
|
|
: Actions.ActOnDeclarator(CurScope, D);
|
2009-05-13 05:31:51 +08:00
|
|
|
|
|
|
|
// Parse declarator '=' initializer.
|
|
|
|
if (Tok.is(tok::equal)) {
|
|
|
|
ConsumeToken();
|
|
|
|
if (getLang().CPlusPlus0x && Tok.is(tok::kw_delete)) {
|
|
|
|
SourceLocation DelLoc = ConsumeToken();
|
|
|
|
Actions.SetDeclDeleted(ThisDecl, DelLoc);
|
|
|
|
} else {
|
2009-06-18 06:50:06 +08:00
|
|
|
if (getLang().CPlusPlus)
|
|
|
|
Actions.ActOnCXXEnterDeclInitializer(CurScope, ThisDecl);
|
|
|
|
|
2009-05-13 05:31:51 +08:00
|
|
|
OwningExprResult Init(ParseInitializer());
|
2009-06-18 06:50:06 +08:00
|
|
|
|
|
|
|
if (getLang().CPlusPlus)
|
|
|
|
Actions.ActOnCXXExitDeclInitializer(CurScope, ThisDecl);
|
|
|
|
|
2009-05-13 05:31:51 +08:00
|
|
|
if (Init.isInvalid()) {
|
|
|
|
SkipUntil(tok::semi, true, true);
|
|
|
|
return DeclPtrTy();
|
|
|
|
}
|
2009-08-16 13:13:48 +08:00
|
|
|
Actions.AddInitializerToDecl(ThisDecl, move(Init));
|
2009-05-13 05:31:51 +08:00
|
|
|
}
|
|
|
|
} else if (Tok.is(tok::l_paren)) {
|
|
|
|
// Parse C++ direct initializer: '(' expression-list ')'
|
|
|
|
SourceLocation LParenLoc = ConsumeParen();
|
|
|
|
ExprVector Exprs(Actions);
|
|
|
|
CommaLocsTy CommaLocs;
|
|
|
|
|
|
|
|
if (ParseExpressionList(Exprs, CommaLocs)) {
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
} else {
|
|
|
|
// Match the ')'.
|
|
|
|
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
|
|
|
|
|
|
|
assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
|
|
|
|
"Unexpected number of commas!");
|
|
|
|
Actions.AddCXXDirectInitializerToDecl(ThisDecl, LParenLoc,
|
|
|
|
move_arg(Exprs),
|
2009-05-21 17:52:38 +08:00
|
|
|
CommaLocs.data(), RParenLoc);
|
2009-05-13 05:31:51 +08:00
|
|
|
}
|
|
|
|
} else {
|
2009-07-11 08:34:39 +08:00
|
|
|
bool TypeContainsUndeducedAuto =
|
|
|
|
D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
|
|
|
|
Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsUndeducedAuto);
|
2009-05-13 05:31:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ThisDecl;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseInitDeclaratorListAfterFirstDeclarator - Parse 'declaration' after
|
|
|
|
/// parsing 'declaration-specifiers declarator'. This method is split out this
|
|
|
|
/// way to handle the ambiguity between top-level function-definitions and
|
|
|
|
/// declarations.
|
|
|
|
///
|
|
|
|
/// init-declarator-list: [C99 6.7]
|
|
|
|
/// init-declarator
|
|
|
|
/// init-declarator-list ',' init-declarator
|
|
|
|
///
|
|
|
|
/// According to the standard grammar, =default and =delete are function
|
|
|
|
/// definitions, but that definitely doesn't fit with the parser here.
|
|
|
|
///
|
2009-03-30 00:50:03 +08:00
|
|
|
Parser::DeclGroupPtrTy Parser::
|
2006-10-16 08:33:54 +08:00
|
|
|
ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
|
2009-03-30 00:50:03 +08:00
|
|
|
// Declarators may be grouped together ("int X, *Y, Z();"). Remember the decls
|
|
|
|
// that we parse together here.
|
|
|
|
llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup;
|
2006-10-16 08:33:54 +08:00
|
|
|
|
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) {
|
2009-05-13 05:31:51 +08:00
|
|
|
DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D);
|
|
|
|
if (ThisDecl.get())
|
|
|
|
DeclsInGroup.push_back(ThisDecl);
|
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
|
2009-02-10 02:23:29 +08:00
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
SourceLocation Loc;
|
|
|
|
AttributeList *AttrList = ParseAttributes(&Loc);
|
|
|
|
D.AddAttributes(AttrList, Loc);
|
|
|
|
}
|
2008-10-20 12:57:38 +08:00
|
|
|
|
2006-08-10 13:19:57 +08:00
|
|
|
ParseDeclarator(D);
|
|
|
|
}
|
|
|
|
|
2009-05-29 09:49:24 +08:00
|
|
|
return Actions.FinalizeDeclaratorGroup(CurScope, D.getDeclSpec(),
|
|
|
|
DeclsInGroup.data(),
|
2009-03-30 01:18:04 +08:00
|
|
|
DeclsInGroup.size());
|
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();
|
2009-04-15 05:16:09 +08:00
|
|
|
if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
|
|
|
|
!DS.getAttributes())
|
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
|
|
|
|
2009-04-13 04:42:31 +08:00
|
|
|
/// isValidAfterIdentifierInDeclaratorAfterDeclSpec - Return true if the
|
|
|
|
/// specified token is valid after the identifier in a declarator which
|
|
|
|
/// immediately follows the declspec. For example, these things are valid:
|
|
|
|
///
|
|
|
|
/// int x [ 4]; // direct-declarator
|
|
|
|
/// int x ( int y); // direct-declarator
|
|
|
|
/// int(int x ) // direct-declarator
|
|
|
|
/// int x ; // simple-declaration
|
|
|
|
/// int x = 17; // init-declarator-list
|
|
|
|
/// int x , y; // init-declarator-list
|
|
|
|
/// int x __asm__ ("foo"); // init-declarator-list
|
2009-04-15 05:16:09 +08:00
|
|
|
/// int x : 4; // struct-declarator
|
2009-04-13 06:29:43 +08:00
|
|
|
/// int x { 5}; // C++'0x unified initializers
|
2009-04-13 04:42:31 +08:00
|
|
|
///
|
|
|
|
/// This is not, because 'x' does not immediately follow the declspec (though
|
|
|
|
/// ')' happens to be valid anyway).
|
|
|
|
/// int (x)
|
|
|
|
///
|
|
|
|
static bool isValidAfterIdentifierInDeclarator(const Token &T) {
|
|
|
|
return T.is(tok::l_square) || T.is(tok::l_paren) || T.is(tok::r_paren) ||
|
|
|
|
T.is(tok::semi) || T.is(tok::comma) || T.is(tok::equal) ||
|
2009-04-15 05:16:09 +08:00
|
|
|
T.is(tok::kw_asm) || T.is(tok::l_brace) || T.is(tok::colon);
|
2009-04-13 04:42:31 +08:00
|
|
|
}
|
|
|
|
|
2009-04-15 05:34:55 +08:00
|
|
|
|
|
|
|
/// ParseImplicitInt - This method is called when we have an non-typename
|
|
|
|
/// identifier in a declspec (which normally terminates the decl spec) when
|
|
|
|
/// the declspec has no type specifier. In this case, the declspec is either
|
|
|
|
/// malformed or is "implicit int" (in K&R and C89).
|
|
|
|
///
|
|
|
|
/// This method handles diagnosing this prettily and returns false if the
|
|
|
|
/// declspec is done being processed. If it recovers and thinks there may be
|
|
|
|
/// other pieces of declspec after it, it returns true.
|
|
|
|
///
|
2009-04-15 06:17:06 +08:00
|
|
|
bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
|
2009-05-13 07:25:50 +08:00
|
|
|
const ParsedTemplateInfo &TemplateInfo,
|
2009-04-15 05:34:55 +08:00
|
|
|
AccessSpecifier AS) {
|
2009-04-15 06:17:06 +08:00
|
|
|
assert(Tok.is(tok::identifier) && "should have identifier");
|
|
|
|
|
2009-04-15 05:34:55 +08:00
|
|
|
SourceLocation Loc = Tok.getLocation();
|
|
|
|
// If we see an identifier that is not a type name, we normally would
|
|
|
|
// parse it as the identifer being declared. However, when a typename
|
|
|
|
// is typo'd or the definition is not included, this will incorrectly
|
|
|
|
// parse the typename as the identifier name and fall over misparsing
|
|
|
|
// later parts of the diagnostic.
|
|
|
|
//
|
|
|
|
// As such, we try to do some look-ahead in cases where this would
|
|
|
|
// otherwise be an "implicit-int" case to see if this is invalid. For
|
|
|
|
// example: "static foo_t x = 4;" In this case, if we parsed foo_t as
|
|
|
|
// an identifier with implicit int, we'd get a parse error because the
|
|
|
|
// next token is obviously invalid for a type. Parse these as a case
|
|
|
|
// with an invalid type specifier.
|
|
|
|
assert(!DS.hasTypeSpecifier() && "Type specifier checked above");
|
|
|
|
|
|
|
|
// Since we know that this either implicit int (which is rare) or an
|
|
|
|
// error, we'd do lookahead to try to do better recovery.
|
|
|
|
if (isValidAfterIdentifierInDeclarator(NextToken())) {
|
|
|
|
// If this token is valid for implicit int, e.g. "static x = 4", then
|
|
|
|
// we just avoid eating the identifier, so it will be parsed as the
|
|
|
|
// identifier in the declarator.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, if we don't consume this token, we are going to emit an
|
|
|
|
// error anyway. Try to recover from various common problems. Check
|
|
|
|
// to see if this was a reference to a tag name without a tag specified.
|
|
|
|
// This is a common problem in C (saying 'foo' instead of 'struct foo').
|
2009-04-15 06:17:06 +08:00
|
|
|
//
|
|
|
|
// C++ doesn't need this, and isTagName doesn't take SS.
|
|
|
|
if (SS == 0) {
|
|
|
|
const char *TagName = 0;
|
|
|
|
tok::TokenKind TagKind = tok::unknown;
|
2009-04-15 05:34:55 +08:00
|
|
|
|
|
|
|
switch (Actions.isTagName(*Tok.getIdentifierInfo(), CurScope)) {
|
|
|
|
default: break;
|
|
|
|
case DeclSpec::TST_enum: TagName="enum" ;TagKind=tok::kw_enum ;break;
|
|
|
|
case DeclSpec::TST_union: TagName="union" ;TagKind=tok::kw_union ;break;
|
|
|
|
case DeclSpec::TST_struct:TagName="struct";TagKind=tok::kw_struct;break;
|
|
|
|
case DeclSpec::TST_class: TagName="class" ;TagKind=tok::kw_class ;break;
|
|
|
|
}
|
|
|
|
|
2009-04-15 06:17:06 +08:00
|
|
|
if (TagName) {
|
|
|
|
Diag(Loc, diag::err_use_of_tag_name_without_tag)
|
|
|
|
<< Tok.getIdentifierInfo() << TagName
|
|
|
|
<< CodeModificationHint::CreateInsertion(Tok.getLocation(),TagName);
|
|
|
|
|
|
|
|
// Parse this as a tag as if the missing tag were present.
|
|
|
|
if (TagKind == tok::kw_enum)
|
|
|
|
ParseEnumSpecifier(Loc, DS, AS);
|
|
|
|
else
|
2009-05-13 07:25:50 +08:00
|
|
|
ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS);
|
2009-04-15 06:17:06 +08:00
|
|
|
return true;
|
|
|
|
}
|
2009-04-15 05:34:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Since this is almost certainly an invalid type name, emit a
|
|
|
|
// diagnostic that says it, eat the token, and mark the declspec as
|
|
|
|
// invalid.
|
2009-04-15 06:17:06 +08:00
|
|
|
SourceRange R;
|
|
|
|
if (SS) R = SS->getRange();
|
|
|
|
|
|
|
|
Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R;
|
2009-04-15 05:34:55 +08:00
|
|
|
const char *PrevSpec;
|
2009-08-04 04:12:06 +08:00
|
|
|
unsigned DiagID;
|
|
|
|
DS.SetTypeSpecType(DeclSpec::TST_error, Loc, PrevSpec, DiagID);
|
2009-04-15 05:34:55 +08:00
|
|
|
DS.SetRangeEnd(Tok.getLocation());
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// TODO: Could inject an invalid typedef decl in an enclosing scope to
|
|
|
|
// avoid rippling error messages on subsequent uses of the same type,
|
|
|
|
// could be useful if #include was forgotten.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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'
|
2009-05-06 12:46:28 +08:00
|
|
|
/// 'friend': [C++ dcl.friend]
|
|
|
|
|
2006-08-04 12:39:53 +08:00
|
|
|
///
|
2008-12-24 10:52:09 +08:00
|
|
|
void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
2009-05-13 07:25:50 +08:00
|
|
|
const ParsedTemplateInfo &TemplateInfo,
|
2009-08-06 10:15:43 +08:00
|
|
|
AccessSpecifier AS,
|
|
|
|
DeclSpecContext DSContext) {
|
2008-03-13 14:29:04 +08:00
|
|
|
DS.SetRangeStart(Tok.getLocation());
|
2006-07-31 13:13:43 +08:00
|
|
|
while (1) {
|
2009-08-04 04:12:06 +08:00
|
|
|
bool isInvalid = false;
|
2006-08-04 12:39:53 +08:00
|
|
|
const char *PrevSpec = 0;
|
2009-08-04 04:12:06 +08:00
|
|
|
unsigned DiagID = 0;
|
|
|
|
|
2006-11-28 13:05:08 +08:00
|
|
|
SourceLocation Loc = Tok.getLocation();
|
2008-11-07 23:42:26 +08:00
|
|
|
|
2006-07-31 13:13:43 +08:00
|
|
|
switch (Tok.getKind()) {
|
2008-11-07 23:42:26 +08:00
|
|
|
default:
|
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.
|
2009-04-02 06:41:11 +08:00
|
|
|
DS.Finish(Diags, PP);
|
2006-08-04 12:39:53 +08:00
|
|
|
return;
|
2009-01-05 08:07:25 +08:00
|
|
|
|
|
|
|
case tok::coloncolon: // ::foo::bar
|
|
|
|
// Annotate C++ scope specifiers. If we get one, loop.
|
Improve support for out-of-line definitions of nested templates and
their members, including member class template, member function
templates, and member classes and functions of member templates.
To actually parse the nested-name-specifiers that qualify the name of
an out-of-line definition of a member template, e.g.,
template<typename X> template<typename Y>
X Outer<X>::Inner1<Y>::foo(Y) {
return X();
}
we need to look for the template names (e.g., "Inner1") as a member of
the current instantiation (Outer<X>), even before we have entered the
scope of the current instantiation. Since we can't do this in general
(i.e., we should not be looking into all dependent
nested-name-specifiers as if they were the current instantiation), we
rely on the parser to tell us when it is parsing a declaration
specifier sequence, and, therefore, when we should consider the
current scope specifier to be a current instantiation.
Printing of complicated, dependent nested-name-specifiers may be
somewhat broken by this commit; I'll add tests for this issue and fix
the problem (if it still exists) in a subsequent commit.
llvm-svn: 80044
2009-08-26 06:51:20 +08:00
|
|
|
if (TryAnnotateCXXScopeToken(true))
|
2009-01-05 08:07:25 +08:00
|
|
|
continue;
|
|
|
|
goto DoneWithDeclSpec;
|
2008-11-09 00:45:02 +08:00
|
|
|
|
|
|
|
case tok::annot_cxxscope: {
|
|
|
|
if (DS.hasTypeSpecifier())
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
|
|
|
// We are looking for a qualified typename.
|
2009-03-25 23:40:00 +08:00
|
|
|
Token Next = NextToken();
|
|
|
|
if (Next.is(tok::annot_template_id) &&
|
|
|
|
static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
|
2009-03-31 08:43:58 +08:00
|
|
|
->Kind == TNK_Type_template) {
|
2009-03-25 23:40:00 +08:00
|
|
|
// We have a qualified template-id, e.g., N::A<int>
|
|
|
|
CXXScopeSpec SS;
|
Improve support for out-of-line definitions of nested templates and
their members, including member class template, member function
templates, and member classes and functions of member templates.
To actually parse the nested-name-specifiers that qualify the name of
an out-of-line definition of a member template, e.g.,
template<typename X> template<typename Y>
X Outer<X>::Inner1<Y>::foo(Y) {
return X();
}
we need to look for the template names (e.g., "Inner1") as a member of
the current instantiation (Outer<X>), even before we have entered the
scope of the current instantiation. Since we can't do this in general
(i.e., we should not be looking into all dependent
nested-name-specifiers as if they were the current instantiation), we
rely on the parser to tell us when it is parsing a declaration
specifier sequence, and, therefore, when we should consider the
current scope specifier to be a current instantiation.
Printing of complicated, dependent nested-name-specifiers may be
somewhat broken by this commit; I'll add tests for this issue and fix
the problem (if it still exists) in a subsequent commit.
llvm-svn: 80044
2009-08-26 06:51:20 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, true);
|
2009-03-25 23:40:00 +08:00
|
|
|
assert(Tok.is(tok::annot_template_id) &&
|
|
|
|
"ParseOptionalCXXScopeSpecifier not working");
|
|
|
|
AnnotateTemplateIdTokenAsType(&SS);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Next.isNot(tok::identifier))
|
2008-11-09 00:45:02 +08:00
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
|
|
|
CXXScopeSpec SS;
|
2009-03-27 07:56:24 +08:00
|
|
|
SS.setScopeRep(Tok.getAnnotationValue());
|
2008-11-09 00:45:02 +08:00
|
|
|
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.
|
2009-04-15 06:17:06 +08:00
|
|
|
if (Actions.isCurrentClassName(*Next.getIdentifierInfo(),
|
2008-11-09 00:45:02 +08:00
|
|
|
CurScope, &SS) &&
|
|
|
|
GetLookAheadToken(2).is(tok::l_paren))
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
2009-02-05 01:00:24 +08:00
|
|
|
TypeTy *TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(),
|
|
|
|
Next.getLocation(), CurScope, &SS);
|
2009-02-10 02:46:07 +08:00
|
|
|
|
2009-04-15 06:17:06 +08:00
|
|
|
// If the referenced identifier is not a type, then this declspec is
|
|
|
|
// erroneous: We already checked about that it has no type specifier, and
|
|
|
|
// C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the
|
|
|
|
// typename.
|
|
|
|
if (TypeRep == 0) {
|
|
|
|
ConsumeToken(); // Eat the scope spec so the identifier is current.
|
2009-05-13 07:25:50 +08:00
|
|
|
if (ParseImplicitInt(DS, &SS, TemplateInfo, AS)) continue;
|
2008-11-09 00:45:02 +08:00
|
|
|
goto DoneWithDeclSpec;
|
2009-04-15 06:17:06 +08:00
|
|
|
}
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
|
2008-11-09 00:45:02 +08:00
|
|
|
ConsumeToken(); // The C++ scope.
|
|
|
|
|
2009-02-09 23:09:02 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
|
2009-08-04 04:12:06 +08:00
|
|
|
DiagID, TypeRep);
|
2008-11-09 00:45:02 +08:00
|
|
|
if (isInvalid)
|
|
|
|
break;
|
|
|
|
|
|
|
|
DS.SetRangeEnd(Tok.getLocation());
|
|
|
|
ConsumeToken(); // The typename.
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2009-01-22 03:48:37 +08:00
|
|
|
|
|
|
|
case tok::annot_typename: {
|
2009-04-02 05:51:26 +08:00
|
|
|
if (Tok.getAnnotationValue())
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
|
2009-08-04 04:12:06 +08:00
|
|
|
DiagID, Tok.getAnnotationValue());
|
2009-04-02 05:51:26 +08:00
|
|
|
else
|
|
|
|
DS.SetTypeSpecError();
|
2009-01-22 03:48:37 +08:00
|
|
|
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
|
|
|
|
ConsumeToken(); // The typename
|
|
|
|
|
|
|
|
// 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;
|
2009-03-29 03:18:32 +08:00
|
|
|
llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
|
2009-01-22 03:48:37 +08:00
|
|
|
ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
|
2009-07-01 06:19:00 +08:00
|
|
|
DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size());
|
2009-01-22 03:48:37 +08:00
|
|
|
|
|
|
|
DS.SetRangeEnd(EndProtoLoc);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-07-26 09:18:38 +08:00
|
|
|
// typedef-name
|
|
|
|
case tok::identifier: {
|
2009-01-05 08:07:25 +08:00
|
|
|
// In C++, check to see if this is a scope specifier like foo::bar::, if
|
|
|
|
// so handle it as such. This is important for ctor parsing.
|
Improve support for out-of-line definitions of nested templates and
their members, including member class template, member function
templates, and member classes and functions of member templates.
To actually parse the nested-name-specifiers that qualify the name of
an out-of-line definition of a member template, e.g.,
template<typename X> template<typename Y>
X Outer<X>::Inner1<Y>::foo(Y) {
return X();
}
we need to look for the template names (e.g., "Inner1") as a member of
the current instantiation (Outer<X>), even before we have entered the
scope of the current instantiation. Since we can't do this in general
(i.e., we should not be looking into all dependent
nested-name-specifiers as if they were the current instantiation), we
rely on the parser to tell us when it is parsing a declaration
specifier sequence, and, therefore, when we should consider the
current scope specifier to be a current instantiation.
Printing of complicated, dependent nested-name-specifiers may be
somewhat broken by this commit; I'll add tests for this issue and fix
the problem (if it still exists) in a subsequent commit.
llvm-svn: 80044
2009-08-26 06:51:20 +08:00
|
|
|
if (getLang().CPlusPlus && TryAnnotateCXXScopeToken(true))
|
2009-01-22 03:19:26 +08:00
|
|
|
continue;
|
2009-01-05 08:07:25 +08:00
|
|
|
|
2008-07-26 09:18:38 +08:00
|
|
|
// 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!
|
2009-02-05 01:00:24 +08:00
|
|
|
TypeTy *TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(),
|
|
|
|
Tok.getLocation(), CurScope);
|
2009-02-10 02:46:07 +08:00
|
|
|
|
2009-04-13 04:42:31 +08:00
|
|
|
// If this is not a typedef name, don't parse it as part of the declspec,
|
|
|
|
// it must be an implicit int or an error.
|
|
|
|
if (TypeRep == 0) {
|
2009-05-13 07:25:50 +08:00
|
|
|
if (ParseImplicitInt(DS, 0, TemplateInfo, AS)) continue;
|
2008-07-26 09:18:38 +08:00
|
|
|
goto DoneWithDeclSpec;
|
2009-04-13 04:42:31 +08:00
|
|
|
}
|
2009-02-10 02:46:07 +08:00
|
|
|
|
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.
|
2009-08-22 02:42:58 +08:00
|
|
|
if (getLang().CPlusPlus &&
|
|
|
|
(CurScope->isClassScope() ||
|
|
|
|
(CurScope->isTemplateParamScope() &&
|
|
|
|
CurScope->getParent()->isClassScope())) &&
|
2008-10-31 17:07:45 +08:00
|
|
|
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) &&
|
|
|
|
NextToken().getKind() == tok::l_paren)
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
2009-02-09 23:09:02 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
|
2009-08-04 04:12:06 +08:00
|
|
|
DiagID, TypeRep);
|
2008-07-26 09:18:38 +08:00
|
|
|
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;
|
2009-03-29 03:18:32 +08:00
|
|
|
llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
|
2008-07-26 12:03:38 +08:00
|
|
|
ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
|
2009-07-01 06:19:00 +08:00
|
|
|
DS.setProtocolQualifiers(ProtocolDecl.data(), 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
|
|
|
}
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
|
|
|
|
// type-name
|
|
|
|
case tok::annot_template_id: {
|
|
|
|
TemplateIdAnnotation *TemplateId
|
|
|
|
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
2009-03-31 08:43:58 +08:00
|
|
|
if (TemplateId->Kind != TNK_Type_template) {
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
// This template-id does not refer to a type name, so we're
|
|
|
|
// done with the type-specifiers.
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Turn the template-id annotation token into a type annotation
|
|
|
|
// token, then try again to parse it as a type-specifier.
|
2009-04-02 05:51:26 +08:00
|
|
|
AnnotateTemplateIdTokenAsType();
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
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;
|
2008-12-25 04:59:21 +08:00
|
|
|
|
|
|
|
// Microsoft declspec support.
|
|
|
|
case tok::kw___declspec:
|
2009-06-08 15:21:15 +08:00
|
|
|
DS.AddAttributes(ParseMicrosoftDeclSpec());
|
2008-12-25 04:59:21 +08:00
|
|
|
continue;
|
2006-08-05 11:28:50 +08:00
|
|
|
|
2008-12-25 22:16:32 +08:00
|
|
|
// Microsoft single token adornments.
|
2008-12-25 22:41:26 +08:00
|
|
|
case tok::kw___forceinline:
|
2009-06-09 07:27:34 +08:00
|
|
|
// FIXME: Add handling here!
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::kw___ptr64:
|
2008-12-25 22:41:26 +08:00
|
|
|
case tok::kw___w64:
|
2008-12-25 22:16:32 +08:00
|
|
|
case tok::kw___cdecl:
|
|
|
|
case tok::kw___stdcall:
|
|
|
|
case tok::kw___fastcall:
|
2009-06-09 07:27:34 +08:00
|
|
|
DS.AddAttributes(ParseMicrosoftTypeAttributes());
|
|
|
|
continue;
|
|
|
|
|
2006-08-05 11:28:50 +08:00
|
|
|
// storage-class-specifier
|
|
|
|
case tok::kw_typedef:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec,
|
|
|
|
DiagID);
|
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";
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec,
|
|
|
|
DiagID);
|
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,
|
2009-08-04 04:12:06 +08:00
|
|
|
PrevSpec, DiagID);
|
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";
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2006-08-05 11:28:50 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_auto:
|
2009-06-27 02:41:36 +08:00
|
|
|
if (getLang().CPlusPlus0x)
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-06-27 02:41:36 +08:00
|
|
|
else
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2006-08-05 11:28:50 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_register:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2006-08-05 11:28:50 +08:00
|
|
|
break;
|
2008-11-15 07:42:31 +08:00
|
|
|
case tok::kw_mutable:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2008-11-15 07:42:31 +08:00
|
|
|
break;
|
2006-08-05 11:28:50 +08:00
|
|
|
case tok::kw___thread:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID);
|
2006-08-05 11:28:50 +08:00
|
|
|
break;
|
2008-11-07 23:42:26 +08:00
|
|
|
|
2006-08-04 12:39:53 +08:00
|
|
|
// function-specifier
|
|
|
|
case tok::kw_inline:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID);
|
2006-08-04 12:39:53 +08:00
|
|
|
break;
|
2008-10-31 17:07:45 +08:00
|
|
|
case tok::kw_virtual:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec, DiagID);
|
2008-10-31 17:07:45 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_explicit:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec, DiagID);
|
2008-10-31 17:07:45 +08:00
|
|
|
break;
|
2009-01-22 03:48:37 +08:00
|
|
|
|
2009-05-06 12:46:28 +08:00
|
|
|
// friend
|
|
|
|
case tok::kw_friend:
|
2009-08-06 10:15:43 +08:00
|
|
|
if (DSContext == DSC_class)
|
|
|
|
isInvalid = DS.SetFriendSpec(Loc, PrevSpec, DiagID);
|
|
|
|
else {
|
|
|
|
PrevSpec = ""; // not actually used by the diagnostic
|
|
|
|
DiagID = diag::err_friend_invalid_in_context;
|
|
|
|
isInvalid = true;
|
|
|
|
}
|
2009-05-06 12:46:28 +08:00
|
|
|
break;
|
2009-08-04 04:12:06 +08:00
|
|
|
|
2009-01-22 03:48:37 +08:00
|
|
|
// type-specifier
|
|
|
|
case tok::kw_short:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_long:
|
|
|
|
if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
else
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_signed:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_unsigned:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw__Complex:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw__Imaginary:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_void:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_char:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_int:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_float:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_double:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_wchar_t:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
2009-07-14 14:30:34 +08:00
|
|
|
case tok::kw_char16_t:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-07-14 14:30:34 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_char32_t:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-07-14 14:30:34 +08:00
|
|
|
break;
|
2009-01-22 03:48:37 +08:00
|
|
|
case tok::kw_bool:
|
|
|
|
case tok::kw__Bool:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw__Decimal32:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw__Decimal64:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw__Decimal128:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
// class-specifier:
|
|
|
|
case tok::kw_class:
|
|
|
|
case tok::kw_struct:
|
2009-04-13 05:49:30 +08:00
|
|
|
case tok::kw_union: {
|
|
|
|
tok::TokenKind Kind = Tok.getKind();
|
|
|
|
ConsumeToken();
|
2009-05-13 07:25:50 +08:00
|
|
|
ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS);
|
2009-01-22 03:48:37 +08:00
|
|
|
continue;
|
2009-04-13 05:49:30 +08:00
|
|
|
}
|
2009-01-22 03:48:37 +08:00
|
|
|
|
|
|
|
// enum-specifier:
|
|
|
|
case tok::kw_enum:
|
2009-04-13 05:49:30 +08:00
|
|
|
ConsumeToken();
|
|
|
|
ParseEnumSpecifier(Loc, DS, AS);
|
2009-01-22 03:48:37 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// cv-qualifier:
|
|
|
|
case tok::kw_const:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID,
|
|
|
|
getLang());
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_volatile:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID,
|
|
|
|
getLang());
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_restrict:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
|
|
|
|
getLang());
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
|
2009-03-28 07:10:48 +08:00
|
|
|
// C++ typename-specifier:
|
|
|
|
case tok::kw_typename:
|
|
|
|
if (TryAnnotateTypeOrScopeToken())
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
|
2009-01-22 03:48:37 +08:00
|
|
|
// GNU typeof support.
|
|
|
|
case tok::kw_typeof:
|
|
|
|
ParseTypeofSpecifier(DS);
|
|
|
|
continue;
|
|
|
|
|
2009-06-25 01:47:40 +08:00
|
|
|
case tok::kw_decltype:
|
|
|
|
ParseDecltypeSpecifier(DS);
|
|
|
|
continue;
|
|
|
|
|
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;
|
2009-03-29 03:18:32 +08:00
|
|
|
llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
|
2008-07-26 12:03:38 +08:00
|
|
|
ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
|
2009-07-01 06:19:00 +08:00
|
|
|
DS.setProtocolQualifiers(ProtocolDecl.data(), 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)
|
2009-04-04 02:38:42 +08:00
|
|
|
<< CodeModificationHint::CreateInsertion(Loc, "id")
|
2008-11-18 15:48:38 +08:00
|
|
|
<< 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
|
|
|
}
|
2009-08-04 04:12:06 +08:00
|
|
|
// If the specifier wasn't legal, issue a diagnostic.
|
2006-08-04 12:39:53 +08:00
|
|
|
if (isInvalid) {
|
|
|
|
assert(PrevSpec && "Method did not return previous specifier!");
|
2009-08-04 04:12:06 +08:00
|
|
|
assert(DiagID);
|
2008-11-18 15:48:38 +08:00
|
|
|
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-12-02 07:54:00 +08:00
|
|
|
|
2009-01-06 14:59:53 +08:00
|
|
|
/// ParseOptionalTypeSpecifier - Try to parse a single type-specifier. We
|
2008-11-07 23:42:26 +08:00
|
|
|
/// 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]
|
2009-06-25 01:47:40 +08:00
|
|
|
/// [C++0x] 'decltype' ( expression )
|
2009-08-04 04:12:06 +08:00
|
|
|
bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
|
2009-01-06 14:59:53 +08:00
|
|
|
const char *&PrevSpec,
|
2009-08-04 04:12:06 +08:00
|
|
|
unsigned &DiagID,
|
2009-05-13 07:25:50 +08:00
|
|
|
const ParsedTemplateInfo &TemplateInfo) {
|
2008-11-07 23:42:26 +08:00
|
|
|
SourceLocation Loc = Tok.getLocation();
|
|
|
|
|
|
|
|
switch (Tok.getKind()) {
|
2009-01-05 07:41:41 +08:00
|
|
|
case tok::identifier: // foo::bar
|
2009-03-28 07:10:48 +08:00
|
|
|
case tok::kw_typename: // typename foo::bar
|
2009-01-05 07:41:41 +08:00
|
|
|
// Annotate typenames and C++ scope specifiers. If we get one, just
|
|
|
|
// recurse to handle whatever we get.
|
|
|
|
if (TryAnnotateTypeOrScopeToken())
|
2009-08-04 04:12:06 +08:00
|
|
|
return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
|
|
|
|
TemplateInfo);
|
2009-01-05 07:41:41 +08:00
|
|
|
// Otherwise, not a type specifier.
|
|
|
|
return false;
|
|
|
|
case tok::coloncolon: // ::foo::bar
|
|
|
|
if (NextToken().is(tok::kw_new) || // ::new
|
|
|
|
NextToken().is(tok::kw_delete)) // ::delete
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Annotate typenames and C++ scope specifiers. If we get one, just
|
|
|
|
// recurse to handle whatever we get.
|
|
|
|
if (TryAnnotateTypeOrScopeToken())
|
2009-08-04 04:12:06 +08:00
|
|
|
return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
|
|
|
|
TemplateInfo);
|
2009-01-05 07:41:41 +08:00
|
|
|
// Otherwise, not a type specifier.
|
|
|
|
return false;
|
|
|
|
|
2008-11-07 23:42:26 +08:00
|
|
|
// simple-type-specifier:
|
2009-01-06 13:06:21 +08:00
|
|
|
case tok::annot_typename: {
|
2009-04-02 05:51:26 +08:00
|
|
|
if (Tok.getAnnotationValue())
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
|
2009-08-04 04:12:06 +08:00
|
|
|
DiagID, Tok.getAnnotationValue());
|
2009-04-02 05:51:26 +08:00
|
|
|
else
|
|
|
|
DS.SetTypeSpecError();
|
2008-11-09 00:45:02 +08:00
|
|
|
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;
|
2009-03-29 03:18:32 +08:00
|
|
|
llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
|
2008-11-07 23:42:26 +08:00
|
|
|
ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
|
2009-07-01 06:19:00 +08:00
|
|
|
DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size());
|
2008-11-07 23:42:26 +08:00
|
|
|
|
|
|
|
DS.SetRangeEnd(EndProtoLoc);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
case tok::kw_short:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_long:
|
|
|
|
if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
else
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_signed:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_unsigned:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw__Complex:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw__Imaginary:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_void:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_char:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_int:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_float:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_double:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_wchar_t:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
2009-07-14 14:30:34 +08:00
|
|
|
case tok::kw_char16_t:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID);
|
2009-07-14 14:30:34 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_char32_t:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID);
|
2009-07-14 14:30:34 +08:00
|
|
|
break;
|
2008-11-07 23:42:26 +08:00
|
|
|
case tok::kw_bool:
|
|
|
|
case tok::kw__Bool:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw__Decimal32:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw__Decimal64:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw__Decimal128:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
// class-specifier:
|
|
|
|
case tok::kw_class:
|
|
|
|
case tok::kw_struct:
|
2009-04-13 05:49:30 +08:00
|
|
|
case tok::kw_union: {
|
|
|
|
tok::TokenKind Kind = Tok.getKind();
|
|
|
|
ConsumeToken();
|
2009-05-13 07:25:50 +08:00
|
|
|
ParseClassSpecifier(Kind, Loc, DS, TemplateInfo);
|
2008-11-07 23:42:26 +08:00
|
|
|
return true;
|
2009-04-13 05:49:30 +08:00
|
|
|
}
|
2008-11-07 23:42:26 +08:00
|
|
|
|
|
|
|
// enum-specifier:
|
|
|
|
case tok::kw_enum:
|
2009-04-13 05:49:30 +08:00
|
|
|
ConsumeToken();
|
|
|
|
ParseEnumSpecifier(Loc, DS);
|
2008-11-07 23:42:26 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// cv-qualifier:
|
|
|
|
case tok::kw_const:
|
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec,
|
2009-08-04 04:12:06 +08:00
|
|
|
DiagID, getLang());
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_volatile:
|
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
|
2009-08-04 04:12:06 +08:00
|
|
|
DiagID, getLang());
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_restrict:
|
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
|
2009-08-04 04:12:06 +08:00
|
|
|
DiagID, getLang());
|
2008-11-07 23:42:26 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
// GNU typeof support.
|
|
|
|
case tok::kw_typeof:
|
|
|
|
ParseTypeofSpecifier(DS);
|
|
|
|
return true;
|
|
|
|
|
2009-06-25 01:47:40 +08:00
|
|
|
// C++0x decltype support.
|
|
|
|
case tok::kw_decltype:
|
|
|
|
ParseDecltypeSpecifier(DS);
|
|
|
|
return true;
|
|
|
|
|
2009-06-27 07:44:14 +08:00
|
|
|
// C++0x auto support.
|
|
|
|
case tok::kw_auto:
|
|
|
|
if (!getLang().CPlusPlus0x)
|
|
|
|
return false;
|
|
|
|
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID);
|
2009-06-27 07:44:14 +08:00
|
|
|
break;
|
2009-06-09 07:27:34 +08:00
|
|
|
case tok::kw___ptr64:
|
|
|
|
case tok::kw___w64:
|
2008-12-25 22:16:32 +08:00
|
|
|
case tok::kw___cdecl:
|
|
|
|
case tok::kw___stdcall:
|
|
|
|
case tok::kw___fastcall:
|
2009-06-09 07:27:34 +08:00
|
|
|
DS.AddAttributes(ParseMicrosoftTypeAttributes());
|
2009-01-22 03:19:26 +08:00
|
|
|
return true;
|
2008-12-25 22:16:32 +08:00
|
|
|
|
2008-11-07 23:42:26 +08:00
|
|
|
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.
|
|
|
|
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);
|
|
|
|
|
2009-01-13 06:49:06 +08:00
|
|
|
// If there are no declarators, this is a free-standing declaration
|
|
|
|
// specifier. Let the actions module cope with it.
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2009-01-13 06:49:06 +08:00
|
|
|
Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
|
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();
|
2008-12-12 05:36:32 +08:00
|
|
|
OwningExprResult Res(ParseConstantExpression());
|
2008-12-09 21:15:23 +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-12-10 08:02:53 +08:00
|
|
|
DeclaratorInfo.BitfieldSize = Res.release();
|
2007-08-21 06:28:22 +08:00
|
|
|
}
|
2009-02-10 02:23:29 +08:00
|
|
|
|
2007-08-21 06:28:22 +08:00
|
|
|
// If attributes exist after the declarator, parse them.
|
2009-02-10 02:23:29 +08:00
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
SourceLocation Loc;
|
|
|
|
AttributeList *AttrList = ParseAttributes(&Loc);
|
|
|
|
DeclaratorInfo.D.AddAttributes(AttrList, Loc);
|
|
|
|
}
|
|
|
|
|
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;
|
2009-02-10 02:23:29 +08:00
|
|
|
|
2007-08-21 06:28:22 +08:00
|
|
|
// Consume the comma.
|
|
|
|
ConsumeToken();
|
2009-02-10 02:23:29 +08:00
|
|
|
|
2007-08-21 06:28:22 +08:00
|
|
|
// Parse the next declarator.
|
2008-04-11 00:37:40 +08:00
|
|
|
Fields.push_back(FieldDeclarator(DS));
|
2009-02-10 02:23:29 +08:00
|
|
|
|
2007-08-21 06:28:22 +08:00
|
|
|
// Attributes are only allowed on the second declarator.
|
2009-02-10 02:23:29 +08:00
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
SourceLocation Loc;
|
|
|
|
AttributeList *AttrList = ParseAttributes(&Loc);
|
|
|
|
Fields.back().D.AddAttributes(AttrList, Loc);
|
|
|
|
}
|
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,
|
2009-03-29 03:18:32 +08:00
|
|
|
unsigned TagType, DeclPtrTy TagDecl) {
|
2009-03-05 16:00:35 +08:00
|
|
|
PrettyStackTraceActionsDecl CrashInfo(TagDecl, RecordLoc, Actions,
|
|
|
|
PP.getSourceManager(),
|
|
|
|
"parsing struct/union body");
|
2009-03-05 10:25:03 +08:00
|
|
|
|
2007-01-23 12:38:16 +08:00
|
|
|
SourceLocation LBraceLoc = ConsumeBrace();
|
|
|
|
|
2009-01-10 06:42:13 +08:00
|
|
|
ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
llvm-svn: 61940
2009-01-09 04:45:30 +08:00
|
|
|
Actions.ActOnTagStartDefinition(CurScope, TagDecl);
|
|
|
|
|
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
|
|
|
|
2009-03-29 03:18:32 +08:00
|
|
|
llvm::SmallVector<DeclPtrTy, 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)) {
|
2009-04-02 06:41:11 +08:00
|
|
|
Diag(Tok, diag::ext_extra_struct_semi)
|
|
|
|
<< CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
|
2007-06-09 13:49:55 +08:00
|
|
|
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];
|
2009-08-26 22:27:30 +08:00
|
|
|
DeclPtrTy Field;
|
2008-06-22 03:39:06 +08:00
|
|
|
// Install the declarator into the current TagDecl.
|
2009-08-26 22:27:30 +08:00
|
|
|
if (FD.D.getExtension()) {
|
|
|
|
// Silences extension warnings
|
|
|
|
ExtensionRAIIObject O(Diags);
|
|
|
|
Field = Actions.ActOnField(CurScope, TagDecl,
|
|
|
|
DS.getSourceRange().getBegin(),
|
|
|
|
FD.D, FD.BitfieldSize);
|
|
|
|
} else {
|
|
|
|
Field = Actions.ActOnField(CurScope, TagDecl,
|
|
|
|
DS.getSourceRange().getBegin(),
|
|
|
|
FD.D, FD.BitfieldSize);
|
|
|
|
}
|
2008-06-22 03:39:06 +08:00
|
|
|
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;
|
|
|
|
}
|
2009-03-29 03:18:32 +08:00
|
|
|
llvm::SmallVector<DeclPtrTy, 16> Fields;
|
2008-12-12 00:49:14 +08:00
|
|
|
Actions.ActOnDefs(CurScope, TagDecl, Tok.getLocation(),
|
|
|
|
Tok.getIdentifierInfo(), Fields);
|
2008-06-22 03:39:06 +08:00
|
|
|
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,
|
2009-05-21 17:52:38 +08:00
|
|
|
RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(),
|
2008-10-03 10:03:53 +08:00
|
|
|
LBraceLoc, RBraceLoc,
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
llvm-svn: 61940
2009-01-09 04:45:30 +08:00
|
|
|
AttrList);
|
|
|
|
StructScope.Exit();
|
2009-07-14 11:17:52 +08:00
|
|
|
Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc);
|
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
|
|
|
|
///
|
2009-04-13 05:49:30 +08:00
|
|
|
void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|
|
|
AccessSpecifier AS) {
|
2007-01-25 15:29:02 +08:00
|
|
|
// 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;
|
2009-01-06 14:59:53 +08:00
|
|
|
if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) {
|
2008-11-09 00:45:02 +08:00
|
|
|
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.
|
|
|
|
//
|
2009-07-31 10:45:11 +08:00
|
|
|
Action::TagUseKind TUK;
|
2008-09-11 08:21:41 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
2009-07-31 10:45:11 +08:00
|
|
|
TUK = Action::TUK_Definition;
|
2008-09-11 08:21:41 +08:00
|
|
|
else if (Tok.is(tok::semi))
|
2009-07-31 10:45:11 +08:00
|
|
|
TUK = Action::TUK_Declaration;
|
2008-09-11 08:21:41 +08:00
|
|
|
else
|
2009-07-31 10:45:11 +08:00
|
|
|
TUK = Action::TUK_Reference;
|
When we parse a tag specifier, keep track of whether that tag
specifier resulted in the creation of a new TagDecl node, which
happens either when the tag specifier was a definition or when the tag
specifier was the first declaration of that tag type. This information
has several uses, the first of which is implemented in this commit:
1) In C++, one is not allowed to define tag types within a type
specifier (e.g., static_cast<struct S { int x; } *>(0) is
ill-formed) or within the result or parameter types of a
function. We now diagnose this.
2) We can extend DeclGroups to contain information about any tags
that are declared/defined within the declaration specifiers of a
variable, e.g.,
struct Point { int x, y, z; } p;
This will help improve AST printing and template instantiation,
among other things.
3) For C99, we can keep track of whether a tag type is defined
within the type of a parameter, to properly cope with cases like,
e.g.,
int bar(struct T2 { int x; } y) {
struct T2 z;
}
We can also do similar things wherever there is a type specifier,
e.g., to keep track of where the definition of S occurs in this
legal C99 code:
(struct S { int x, y; } *)0
llvm-svn: 72555
2009-05-29 07:31:59 +08:00
|
|
|
bool Owned = false;
|
2009-07-31 10:45:11 +08:00
|
|
|
DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK,
|
When we parse a tag specifier, keep track of whether that tag
specifier resulted in the creation of a new TagDecl node, which
happens either when the tag specifier was a definition or when the tag
specifier was the first declaration of that tag type. This information
has several uses, the first of which is implemented in this commit:
1) In C++, one is not allowed to define tag types within a type
specifier (e.g., static_cast<struct S { int x; } *>(0) is
ill-formed) or within the result or parameter types of a
function. We now diagnose this.
2) We can extend DeclGroups to contain information about any tags
that are declared/defined within the declaration specifiers of a
variable, e.g.,
struct Point { int x, y, z; } p;
This will help improve AST printing and template instantiation,
among other things.
3) For C99, we can keep track of whether a tag type is defined
within the type of a parameter, to properly cope with cases like,
e.g.,
int bar(struct T2 { int x; } y) {
struct T2 z;
}
We can also do similar things wherever there is a type specifier,
e.g., to keep track of where the definition of S occurs in this
legal C99 code:
(struct S { int x, y; } *)0
llvm-svn: 72555
2009-05-29 07:31:59 +08:00
|
|
|
StartLoc, SS, Name, NameLoc, Attr, AS,
|
2009-07-24 00:36:45 +08:00
|
|
|
Action::MultiTemplateParamsArg(Actions),
|
When we parse a tag specifier, keep track of whether that tag
specifier resulted in the creation of a new TagDecl node, which
happens either when the tag specifier was a definition or when the tag
specifier was the first declaration of that tag type. This information
has several uses, the first of which is implemented in this commit:
1) In C++, one is not allowed to define tag types within a type
specifier (e.g., static_cast<struct S { int x; } *>(0) is
ill-formed) or within the result or parameter types of a
function. We now diagnose this.
2) We can extend DeclGroups to contain information about any tags
that are declared/defined within the declaration specifiers of a
variable, e.g.,
struct Point { int x, y, z; } p;
This will help improve AST printing and template instantiation,
among other things.
3) For C99, we can keep track of whether a tag type is defined
within the type of a parameter, to properly cope with cases like,
e.g.,
int bar(struct T2 { int x; } y) {
struct T2 z;
}
We can also do similar things wherever there is a type specifier,
e.g., to keep track of where the definition of S occurs in this
legal C99 code:
(struct S { int x, y; } *)0
llvm-svn: 72555
2009-05-29 07:31:59 +08:00
|
|
|
Owned);
|
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;
|
2009-08-04 04:12:06 +08:00
|
|
|
unsigned DiagID;
|
|
|
|
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, DiagID,
|
When we parse a tag specifier, keep track of whether that tag
specifier resulted in the creation of a new TagDecl node, which
happens either when the tag specifier was a definition or when the tag
specifier was the first declaration of that tag type. This information
has several uses, the first of which is implemented in this commit:
1) In C++, one is not allowed to define tag types within a type
specifier (e.g., static_cast<struct S { int x; } *>(0) is
ill-formed) or within the result or parameter types of a
function. We now diagnose this.
2) We can extend DeclGroups to contain information about any tags
that are declared/defined within the declaration specifiers of a
variable, e.g.,
struct Point { int x, y, z; } p;
This will help improve AST printing and template instantiation,
among other things.
3) For C99, we can keep track of whether a tag type is defined
within the type of a parameter, to properly cope with cases like,
e.g.,
int bar(struct T2 { int x; } y) {
struct T2 z;
}
We can also do similar things wherever there is a type specifier,
e.g., to keep track of where the definition of S occurs in this
legal C99 code:
(struct S { int x, y; } *)0
llvm-svn: 72555
2009-05-29 07:31:59 +08:00
|
|
|
TagDecl.getAs<void>(), Owned))
|
2009-08-04 04:12:06 +08:00
|
|
|
Diag(StartLoc, DiagID) << 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
|
|
|
|
///
|
2009-03-29 03:18:32 +08:00
|
|
|
void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) {
|
2009-01-06 03:45:36 +08:00
|
|
|
// Enter the scope of the enum body and start the definition.
|
|
|
|
ParseScope EnumScope(this, Scope::DeclScope);
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
llvm-svn: 61940
2009-01-09 04:45:30 +08:00
|
|
|
Actions.ActOnTagStartDefinition(CurScope, EnumDecl);
|
2009-01-06 03:45:36 +08:00
|
|
|
|
2007-01-25 15:29:02 +08:00
|
|
|
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
|
|
|
|
2009-03-29 03:18:32 +08:00
|
|
|
llvm::SmallVector<DeclPtrTy, 32> EnumConstantDecls;
|
2007-01-25 15:29:02 +08:00
|
|
|
|
2009-03-29 03:18:32 +08:00
|
|
|
DeclPtrTy LastEnumConstDecl;
|
2007-06-11 09:28:17 +08:00
|
|
|
|
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;
|
2008-12-10 04:22:58 +08:00
|
|
|
OwningExprResult AssignedVal(Actions);
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::equal)) {
|
2007-01-25 15:29:02 +08:00
|
|
|
EqualLoc = ConsumeToken();
|
2008-12-09 21:15:23 +08:00
|
|
|
AssignedVal = ParseConstantExpression();
|
|
|
|
if (AssignedVal.isInvalid())
|
2007-04-28 03:13:15 +08:00
|
|
|
SkipUntil(tok::comma, tok::r_brace, true, true);
|
2006-08-13 08:12:11 +08:00
|
|
|
}
|
|
|
|
|
2007-01-25 15:29:02 +08:00
|
|
|
// Install the enumerator constant into EnumDecl.
|
2009-03-29 03:18:32 +08:00
|
|
|
DeclPtrTy EnumConstDecl = Actions.ActOnEnumConstant(CurScope, EnumDecl,
|
|
|
|
LastEnumConstDecl,
|
|
|
|
IdentLoc, Ident,
|
|
|
|
EqualLoc,
|
|
|
|
AssignedVal.release());
|
2007-06-11 09:28:17 +08:00
|
|
|
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();
|
|
|
|
|
2009-04-02 06:41:11 +08:00
|
|
|
if (Tok.isNot(tok::identifier) &&
|
|
|
|
!(getLang().C99 || getLang().CPlusPlus0x))
|
|
|
|
Diag(CommaLoc, diag::ext_enumerator_list_comma)
|
|
|
|
<< getLang().CPlusPlus
|
|
|
|
<< CodeModificationHint::CreateRemoval((SourceRange(CommaLoc)));
|
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 }.
|
2009-05-16 15:06:02 +08:00
|
|
|
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
|
2007-01-25 15:29:02 +08:00
|
|
|
|
2009-08-08 22:36:57 +08:00
|
|
|
AttributeList *Attr = 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))
|
2009-08-08 22:36:57 +08:00
|
|
|
Attr = ParseAttributes();
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
llvm-svn: 61940
2009-01-09 04:45:30 +08:00
|
|
|
|
2009-08-08 22:36:57 +08:00
|
|
|
Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl,
|
|
|
|
EnumConstantDecls.data(), EnumConstantDecls.size(),
|
|
|
|
CurScope, Attr);
|
|
|
|
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
llvm-svn: 61940
2009-01-09 04:45:30 +08:00
|
|
|
EnumScope.Exit();
|
2009-07-14 11:17:52 +08:00
|
|
|
Actions.ActOnTagFinishDefinition(CurScope, EnumDecl, RBraceLoc);
|
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() {
|
2006-08-11 07:56:11 +08:00
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default: return false;
|
2009-01-05 07:41:41 +08:00
|
|
|
|
|
|
|
case tok::identifier: // foo::bar
|
2009-03-28 07:10:48 +08:00
|
|
|
case tok::kw_typename: // typename T::type
|
2009-01-05 07:41:41 +08:00
|
|
|
// Annotate typenames and C++ scope specifiers. If we get one, just
|
|
|
|
// recurse to handle whatever we get.
|
|
|
|
if (TryAnnotateTypeOrScopeToken())
|
|
|
|
return isTypeSpecifierQualifier();
|
|
|
|
// Otherwise, not a type specifier.
|
|
|
|
return false;
|
2009-03-28 07:10:48 +08:00
|
|
|
|
2009-01-05 07:41:41 +08:00
|
|
|
case tok::coloncolon: // ::foo::bar
|
|
|
|
if (NextToken().is(tok::kw_new) || // ::new
|
|
|
|
NextToken().is(tok::kw_delete)) // ::delete
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Annotate typenames and C++ scope specifiers. If we get one, just
|
|
|
|
// recurse to handle whatever we get.
|
|
|
|
if (TryAnnotateTypeOrScopeToken())
|
|
|
|
return isTypeSpecifierQualifier();
|
|
|
|
// Otherwise, not a type specifier.
|
|
|
|
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:
|
2009-07-14 14:30:34 +08:00
|
|
|
case tok::kw_char16_t:
|
|
|
|
case tok::kw_char32_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
|
2009-01-06 13:06:21 +08:00
|
|
|
case tok::annot_typename:
|
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;
|
2008-12-25 22:16:32 +08:00
|
|
|
|
|
|
|
case tok::kw___cdecl:
|
|
|
|
case tok::kw___stdcall:
|
|
|
|
case tok::kw___fastcall:
|
2009-06-09 07:27:34 +08:00
|
|
|
case tok::kw___w64:
|
|
|
|
case tok::kw___ptr64:
|
|
|
|
return true;
|
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() {
|
2006-08-07 01:24:14 +08:00
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default: return false;
|
2009-01-05 07:41:41 +08:00
|
|
|
|
|
|
|
case tok::identifier: // foo::bar
|
2009-03-10 05:12:44 +08:00
|
|
|
// Unfortunate hack to support "Class.factoryMethod" notation.
|
|
|
|
if (getLang().ObjC1 && NextToken().is(tok::period))
|
|
|
|
return false;
|
2009-03-28 07:10:48 +08:00
|
|
|
// Fall through
|
2009-03-10 05:12:44 +08:00
|
|
|
|
2009-03-28 07:10:48 +08:00
|
|
|
case tok::kw_typename: // typename T::type
|
2009-01-05 07:41:41 +08:00
|
|
|
// Annotate typenames and C++ scope specifiers. If we get one, just
|
|
|
|
// recurse to handle whatever we get.
|
|
|
|
if (TryAnnotateTypeOrScopeToken())
|
|
|
|
return isDeclarationSpecifier();
|
|
|
|
// Otherwise, not a declaration specifier.
|
|
|
|
return false;
|
|
|
|
case tok::coloncolon: // ::foo::bar
|
|
|
|
if (NextToken().is(tok::kw_new) || // ::new
|
|
|
|
NextToken().is(tok::kw_delete)) // ::delete
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Annotate typenames and C++ scope specifiers. If we get one, just
|
|
|
|
// recurse to handle whatever we get.
|
|
|
|
if (TryAnnotateTypeOrScopeToken())
|
|
|
|
return isDeclarationSpecifier();
|
|
|
|
// Otherwise, not a declaration specifier.
|
|
|
|
return false;
|
|
|
|
|
2006-08-07 01:24:14 +08:00
|
|
|
// 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:
|
2009-07-14 14:30:34 +08:00
|
|
|
case tok::kw_char16_t:
|
|
|
|
case tok::kw_char32_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
|
2009-01-06 13:06:21 +08:00
|
|
|
case tok::annot_typename:
|
2008-11-09 00:45:02 +08:00
|
|
|
|
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;
|
2008-12-25 22:16:32 +08:00
|
|
|
|
2009-01-07 03:34:12 +08:00
|
|
|
case tok::kw___declspec:
|
2008-12-25 22:16:32 +08:00
|
|
|
case tok::kw___cdecl:
|
|
|
|
case tok::kw___stdcall:
|
|
|
|
case tok::kw___fastcall:
|
2009-06-09 07:27:34 +08:00
|
|
|
case tok::kw___w64:
|
|
|
|
case tok::kw___ptr64:
|
|
|
|
case tok::kw___forceinline:
|
|
|
|
return true;
|
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
|
2008-12-18 15:02:59 +08:00
|
|
|
/// [GNU] attributes [ only if AttributesAllowed=true ]
|
2006-07-31 13:13:43 +08:00
|
|
|
/// type-qualifier-list type-qualifier
|
2008-12-18 15:02:59 +08:00
|
|
|
/// [GNU] type-qualifier-list attributes [ only if AttributesAllowed=true ]
|
2006-07-31 13:13:43 +08:00
|
|
|
///
|
2008-12-18 15:02:59 +08:00
|
|
|
void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) {
|
2006-07-31 13:13:43 +08:00
|
|
|
while (1) {
|
2009-08-04 04:12:06 +08:00
|
|
|
bool isInvalid = false;
|
2006-08-05 14:26:47 +08:00
|
|
|
const char *PrevSpec = 0;
|
2009-08-04 04:12:06 +08:00
|
|
|
unsigned DiagID = 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()) {
|
|
|
|
case tok::kw_const:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID,
|
|
|
|
getLang());
|
2006-08-05 14:26:47 +08:00
|
|
|
break;
|
2006-07-31 13:13:43 +08:00
|
|
|
case tok::kw_volatile:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID,
|
|
|
|
getLang());
|
2006-08-05 14:26:47 +08:00
|
|
|
break;
|
2006-07-31 13:13:43 +08:00
|
|
|
case tok::kw_restrict:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
|
|
|
|
getLang());
|
2006-07-31 13:13:43 +08:00
|
|
|
break;
|
2009-06-09 07:27:34 +08:00
|
|
|
case tok::kw___w64:
|
2008-12-25 22:41:26 +08:00
|
|
|
case tok::kw___ptr64:
|
2008-12-25 22:16:32 +08:00
|
|
|
case tok::kw___cdecl:
|
|
|
|
case tok::kw___stdcall:
|
|
|
|
case tok::kw___fastcall:
|
2009-06-09 07:27:34 +08:00
|
|
|
if (AttributesAllowed) {
|
|
|
|
DS.AddAttributes(ParseMicrosoftTypeAttributes());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
goto DoneWithTypeQuals;
|
2006-08-15 12:50:22 +08:00
|
|
|
case tok::kw___attribute:
|
2008-12-18 15:02:59 +08:00
|
|
|
if (AttributesAllowed) {
|
|
|
|
DS.AddAttributes(ParseAttributes());
|
|
|
|
continue; // do *not* consume the next token!
|
|
|
|
}
|
|
|
|
// otherwise, FALL THROUGH!
|
|
|
|
default:
|
2008-12-25 22:16:32 +08:00
|
|
|
DoneWithTypeQuals:
|
2008-12-18 15:02:59 +08:00
|
|
|
// If this is not a type-qualifier token, we're done reading type
|
|
|
|
// qualifiers. First verify that DeclSpec's are consistent.
|
2009-04-02 06:41:11 +08:00
|
|
|
DS.Finish(Diags, PP);
|
2008-12-18 15:02:59 +08:00
|
|
|
return;
|
2006-07-31 13:13:43 +08:00
|
|
|
}
|
2008-12-18 14:50:14 +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
|
|
|
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.
|
|
|
|
///
|
2009-01-25 05:16:55 +08:00
|
|
|
/// declarator: [C99 6.7.5] [C++ 8p4, dcl.decl]
|
|
|
|
/// [C] pointer[opt] direct-declarator
|
|
|
|
/// [C++] direct-declarator
|
|
|
|
/// [C++] ptr-operator 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]
|
|
|
|
/// '&'
|
2009-03-16 06:02:01 +08:00
|
|
|
/// [C++0x] '&&'
|
2008-11-08 04:08:42 +08:00
|
|
|
/// [GNU] '&' restrict[opt] attributes[opt]
|
2009-03-16 06:02:01 +08:00
|
|
|
/// [GNU?] '&&' restrict[opt] attributes[opt]
|
2009-01-25 05:16:55 +08:00
|
|
|
/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt]
|
2008-11-22 03:14:01 +08:00
|
|
|
void Parser::ParseDeclaratorInternal(Declarator &D,
|
|
|
|
DirectDeclParseFunction DirectDeclParser) {
|
2007-05-27 18:15:43 +08:00
|
|
|
|
2009-08-26 22:27:30 +08:00
|
|
|
if (Diags.hasAllExtensionsSilenced())
|
|
|
|
D.setExtension();
|
2009-01-25 05:16:55 +08:00
|
|
|
// C++ member pointers start with a '::' or a nested-name.
|
|
|
|
// Member pointers get special handling, since there's no place for the
|
|
|
|
// scope spec in the generic path below.
|
2009-03-25 01:04:48 +08:00
|
|
|
if (getLang().CPlusPlus &&
|
|
|
|
(Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||
|
|
|
|
Tok.is(tok::annot_cxxscope))) {
|
2009-01-25 05:16:55 +08:00
|
|
|
CXXScopeSpec SS;
|
Improve support for out-of-line definitions of nested templates and
their members, including member class template, member function
templates, and member classes and functions of member templates.
To actually parse the nested-name-specifiers that qualify the name of
an out-of-line definition of a member template, e.g.,
template<typename X> template<typename Y>
X Outer<X>::Inner1<Y>::foo(Y) {
return X();
}
we need to look for the template names (e.g., "Inner1") as a member of
the current instantiation (Outer<X>), even before we have entered the
scope of the current instantiation. Since we can't do this in general
(i.e., we should not be looking into all dependent
nested-name-specifiers as if they were the current instantiation), we
rely on the parser to tell us when it is parsing a declaration
specifier sequence, and, therefore, when we should consider the
current scope specifier to be a current instantiation.
Printing of complicated, dependent nested-name-specifiers may be
somewhat broken by this commit; I'll add tests for this issue and fix
the problem (if it still exists) in a subsequent commit.
llvm-svn: 80044
2009-08-26 06:51:20 +08:00
|
|
|
if (ParseOptionalCXXScopeSpecifier(SS, true)) {
|
2009-01-25 05:16:55 +08:00
|
|
|
if(Tok.isNot(tok::star)) {
|
|
|
|
// The scope spec really belongs to the direct-declarator.
|
|
|
|
D.getCXXScopeSpec() = SS;
|
|
|
|
if (DirectDeclParser)
|
|
|
|
(this->*DirectDeclParser)(D);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation Loc = ConsumeToken();
|
2009-02-10 02:23:29 +08:00
|
|
|
D.SetRangeEnd(Loc);
|
2009-01-25 05:16:55 +08:00
|
|
|
DeclSpec DS;
|
|
|
|
ParseTypeQualifierListOpt(DS);
|
2009-02-10 02:23:29 +08:00
|
|
|
D.ExtendWithDeclSpec(DS);
|
2009-01-25 05:16:55 +08:00
|
|
|
|
|
|
|
// Recurse to parse whatever is left.
|
|
|
|
ParseDeclaratorInternal(D, DirectDeclParser);
|
|
|
|
|
|
|
|
// Sema will have to catch (syntactically invalid) pointers into global
|
|
|
|
// scope. It has to catch pointers into namespace scope anyway.
|
|
|
|
D.AddTypeInfo(DeclaratorChunk::getMemberPointer(SS,DS.getTypeQualifiers(),
|
2009-02-10 02:23:29 +08:00
|
|
|
Loc, DS.TakeAttributes()),
|
|
|
|
/* Don't replace range end. */SourceLocation());
|
2009-01-25 05:16:55 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tok::TokenKind Kind = Tok.getKind();
|
2008-08-28 00:04:49 +08:00
|
|
|
// Not a pointer, C++ reference, or block.
|
2009-03-27 12:18:06 +08:00
|
|
|
if (Kind != tok::star && Kind != tok::caret &&
|
2009-03-25 01:04:48 +08:00
|
|
|
(Kind != tok::amp || !getLang().CPlusPlus) &&
|
2009-03-23 08:00:23 +08:00
|
|
|
// We parse rvalue refs in C++03, because otherwise the errors are scary.
|
2009-03-27 12:18:06 +08:00
|
|
|
(Kind != tok::ampamp || !getLang().CPlusPlus)) {
|
2008-11-22 03:14:01 +08:00
|
|
|
if (DirectDeclParser)
|
|
|
|
(this->*DirectDeclParser)(D);
|
2008-11-08 04:08:42 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-01-25 05:16:55 +08:00
|
|
|
|
2009-03-16 06:02:01 +08:00
|
|
|
// Otherwise, '*' -> pointer, '^' -> block, '&' -> lvalue reference,
|
|
|
|
// '&&' -> rvalue reference
|
2009-03-23 08:00:23 +08:00
|
|
|
SourceLocation Loc = ConsumeToken(); // Eat the *, ^, & or &&.
|
2009-02-10 02:23:29 +08:00
|
|
|
D.SetRangeEnd(Loc);
|
2007-05-27 18:15:43 +08:00
|
|
|
|
2009-03-27 12:18:06 +08:00
|
|
|
if (Kind == tok::star || Kind == tok::caret) {
|
2008-02-21 09:32:26 +08:00
|
|
|
// Is a pointer.
|
2007-05-27 18:15:43 +08:00
|
|
|
DeclSpec DS;
|
2009-01-25 05:16:55 +08:00
|
|
|
|
2007-05-27 18:15:43 +08:00
|
|
|
ParseTypeQualifierListOpt(DS);
|
2009-02-10 02:23:29 +08:00
|
|
|
D.ExtendWithDeclSpec(DS);
|
2009-01-25 05:16:55 +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,
|
2009-02-10 02:23:29 +08:00
|
|
|
DS.TakeAttributes()),
|
|
|
|
SourceLocation());
|
2008-08-28 00:04:49 +08:00
|
|
|
else
|
|
|
|
// Remember that we parsed a Block type, and remember the type-quals.
|
|
|
|
D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(),
|
2009-04-21 08:51:43 +08:00
|
|
|
Loc, DS.TakeAttributes()),
|
2009-02-10 02:23:29 +08:00
|
|
|
SourceLocation());
|
2007-05-27 18:15:43 +08:00
|
|
|
} else {
|
|
|
|
// Is a reference
|
2007-06-03 07:28:54 +08:00
|
|
|
DeclSpec DS;
|
|
|
|
|
2009-03-23 08:00:23 +08:00
|
|
|
// Complain about rvalue references in C++03, but then go on and build
|
|
|
|
// the declarator.
|
|
|
|
if (Kind == tok::ampamp && !getLang().CPlusPlus0x)
|
|
|
|
Diag(Loc, diag::err_rvalue_reference);
|
|
|
|
|
2007-06-03 07:28:54 +08:00
|
|
|
// 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);
|
2009-02-10 02:23:29 +08:00
|
|
|
D.ExtendWithDeclSpec(DS);
|
2007-06-03 07:28:54 +08:00
|
|
|
|
|
|
|
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,
|
2009-03-16 06:02:01 +08:00
|
|
|
DS.TakeAttributes(),
|
|
|
|
Kind == tok::amp),
|
2009-02-10 02:23:29 +08:00
|
|
|
SourceLocation());
|
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
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
/// template-id
|
2008-11-08 06:02:30 +08:00
|
|
|
///
|
2006-08-07 01:24:14 +08:00
|
|
|
void Parser::ParseDirectDeclarator(Declarator &D) {
|
2008-11-27 06:40:03 +08:00
|
|
|
DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec());
|
|
|
|
|
|
|
|
if (getLang().CPlusPlus) {
|
|
|
|
if (D.mayHaveIdentifier()) {
|
2009-01-25 05:16:55 +08:00
|
|
|
// ParseDeclaratorInternal might already have parsed the scope.
|
|
|
|
bool afterCXXScope = D.getCXXScopeSpec().isSet() ||
|
Improve support for out-of-line definitions of nested templates and
their members, including member class template, member function
templates, and member classes and functions of member templates.
To actually parse the nested-name-specifiers that qualify the name of
an out-of-line definition of a member template, e.g.,
template<typename X> template<typename Y>
X Outer<X>::Inner1<Y>::foo(Y) {
return X();
}
we need to look for the template names (e.g., "Inner1") as a member of
the current instantiation (Outer<X>), even before we have entered the
scope of the current instantiation. Since we can't do this in general
(i.e., we should not be looking into all dependent
nested-name-specifiers as if they were the current instantiation), we
rely on the parser to tell us when it is parsing a declaration
specifier sequence, and, therefore, when we should consider the
current scope specifier to be a current instantiation.
Printing of complicated, dependent nested-name-specifiers may be
somewhat broken by this commit; I'll add tests for this issue and fix
the problem (if it still exists) in a subsequent commit.
llvm-svn: 80044
2009-08-26 06:51:20 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), true);
|
2008-11-27 06:40:03 +08:00
|
|
|
if (afterCXXScope) {
|
|
|
|
// Change the declaration context for name lookup, until this function
|
|
|
|
// is exited (and the declarator has been parsed).
|
|
|
|
DeclScopeObj.EnterDeclaratorScope();
|
|
|
|
}
|
2008-11-09 00:45:02 +08:00
|
|
|
|
2008-11-27 06:40:03 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
|
|
|
assert(Tok.getIdentifierInfo() && "Not an identifier?");
|
2009-05-01 06:41:11 +08:00
|
|
|
|
|
|
|
// If this identifier is the name of the current class, it's a
|
|
|
|
// constructor name.
|
|
|
|
if (!D.getDeclSpec().hasTypeSpecifier() &&
|
|
|
|
Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)) {
|
2009-07-07 00:40:48 +08:00
|
|
|
CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0;
|
2009-05-01 06:41:11 +08:00
|
|
|
D.setConstructor(Actions.getTypeName(*Tok.getIdentifierInfo(),
|
2009-07-07 00:40:48 +08:00
|
|
|
Tok.getLocation(), CurScope, SS),
|
2009-05-01 06:41:11 +08:00
|
|
|
Tok.getLocation());
|
|
|
|
// This is a normal identifier.
|
|
|
|
} else
|
|
|
|
D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
|
2008-11-27 06:40:03 +08:00
|
|
|
ConsumeToken();
|
|
|
|
goto PastIdentifier;
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
} else if (Tok.is(tok::annot_template_id)) {
|
|
|
|
TemplateIdAnnotation *TemplateId
|
|
|
|
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
|
|
|
|
|
|
|
// FIXME: Could this template-id name a constructor?
|
|
|
|
|
|
|
|
// FIXME: This is an egregious hack, where we silently ignore
|
|
|
|
// the specialization (which should be a function template
|
|
|
|
// specialization name) and use the name instead. This hack
|
|
|
|
// will go away when we have support for function
|
|
|
|
// specializations.
|
|
|
|
D.SetIdentifier(TemplateId->Name, Tok.getLocation());
|
|
|
|
TemplateId->Destroy();
|
|
|
|
ConsumeToken();
|
|
|
|
goto PastIdentifier;
|
2008-12-26 23:00:45 +08:00
|
|
|
} else if (Tok.is(tok::kw_operator)) {
|
|
|
|
SourceLocation OperatorLoc = Tok.getLocation();
|
2009-02-10 02:23:29 +08:00
|
|
|
SourceLocation EndLoc;
|
2008-11-27 06:40:03 +08:00
|
|
|
|
2008-12-26 23:00:45 +08:00
|
|
|
// First try the name of an overloaded operator
|
2009-02-10 02:23:29 +08:00
|
|
|
if (OverloadedOperatorKind Op = TryParseOperatorFunctionId(&EndLoc)) {
|
|
|
|
D.setOverloadedOperator(Op, OperatorLoc, EndLoc);
|
2008-12-26 23:00:45 +08:00
|
|
|
} else {
|
|
|
|
// This must be a conversion function (C++ [class.conv.fct]).
|
2009-02-10 02:23:29 +08:00
|
|
|
if (TypeTy *ConvType = ParseConversionFunctionId(&EndLoc))
|
|
|
|
D.setConversionFunction(ConvType, OperatorLoc, EndLoc);
|
|
|
|
else {
|
2008-12-26 23:00:45 +08:00
|
|
|
D.SetIdentifier(0, Tok.getLocation());
|
2009-02-10 02:23:29 +08:00
|
|
|
}
|
2008-12-26 23:00:45 +08:00
|
|
|
}
|
|
|
|
goto PastIdentifier;
|
|
|
|
} else if (Tok.is(tok::tilde)) {
|
2008-11-27 06:40:03 +08:00
|
|
|
// This should be a C++ destructor.
|
|
|
|
SourceLocation TildeLoc = ConsumeToken();
|
2009-08-27 02:27:52 +08:00
|
|
|
if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) {
|
2009-02-10 02:23:29 +08:00
|
|
|
// FIXME: Inaccurate.
|
|
|
|
SourceLocation NameLoc = Tok.getLocation();
|
2009-02-26 07:52:28 +08:00
|
|
|
SourceLocation EndLoc;
|
2009-07-07 00:40:48 +08:00
|
|
|
CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0;
|
2009-07-21 01:43:15 +08:00
|
|
|
TypeResult Type = ParseClassName(EndLoc, SS, true);
|
2009-04-02 05:51:26 +08:00
|
|
|
if (Type.isInvalid())
|
2008-11-27 06:40:03 +08:00
|
|
|
D.SetIdentifier(0, TildeLoc);
|
2009-04-02 05:51:26 +08:00
|
|
|
else
|
|
|
|
D.setDestructor(Type.get(), TildeLoc, NameLoc);
|
2008-11-27 06:40:03 +08:00
|
|
|
} else {
|
2009-07-21 01:43:15 +08:00
|
|
|
Diag(Tok, diag::err_destructor_class_name);
|
2008-11-27 06:40:03 +08:00
|
|
|
D.SetIdentifier(0, TildeLoc);
|
|
|
|
}
|
|
|
|
goto PastIdentifier;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we reached this point, token is not identifier and not '~'.
|
|
|
|
|
|
|
|
if (afterCXXScope) {
|
|
|
|
Diag(Tok, diag::err_expected_unqualified_id);
|
|
|
|
D.SetIdentifier(0, Tok.getLocation());
|
|
|
|
D.setInvalidType(true);
|
|
|
|
goto PastIdentifier;
|
|
|
|
}
|
2008-11-08 06:02:30 +08:00
|
|
|
}
|
2008-11-27 06:40:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we reached this point, we are either in C/ObjC or the token didn't
|
|
|
|
// satisfy any of the C++-specific checks.
|
|
|
|
if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) {
|
|
|
|
assert(!getLang().CPlusPlus &&
|
|
|
|
"There's a C++-specific check for tok::identifier above");
|
|
|
|
assert(Tok.getIdentifierInfo() && "Not an identifier?");
|
|
|
|
D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
|
|
|
|
ConsumeToken();
|
|
|
|
} else if (Tok.is(tok::l_paren)) {
|
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-27 06:40:03 +08:00
|
|
|
} else if (D.mayOmitIdentifier()) {
|
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 {
|
2009-03-07 07:28:18 +08:00
|
|
|
if (D.getContext() == Declarator::MemberContext)
|
|
|
|
Diag(Tok, diag::err_expected_member_name_or_semi)
|
|
|
|
<< D.getDeclSpec().getSourceRange();
|
|
|
|
else if (getLang().CPlusPlus)
|
2008-11-09 00:45:02 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2008-11-27 06:40:03 +08:00
|
|
|
PastIdentifier:
|
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-12-25 22:16:32 +08:00
|
|
|
// Eat any Microsoft extensions.
|
2009-06-09 07:27:34 +08:00
|
|
|
if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) ||
|
|
|
|
Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___w64) ||
|
|
|
|
Tok.is(tok::kw___ptr64)) {
|
|
|
|
AttrList = ParseMicrosoftTypeAttributes(AttrList);
|
|
|
|
}
|
2008-10-20 10:05:46 +08:00
|
|
|
|
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)
|
2009-02-10 02:23:29 +08:00
|
|
|
D.AddAttributes(AttrList, SourceLocation());
|
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 ')'.
|
2009-02-10 02:23:29 +08:00
|
|
|
SourceLocation Loc = MatchRHSPunctuation(tok::r_paren, StartLoc);
|
2008-10-07 18:21:57 +08:00
|
|
|
|
|
|
|
D.setGroupingParens(hadGroupingParens);
|
2009-02-10 02:23:29 +08:00
|
|
|
D.SetRangeEnd(Loc);
|
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
|
2009-03-25 06:27:57 +08:00
|
|
|
/// declaration-specifiers abstract-declarator[opt]
|
|
|
|
/// [C++] declaration-specifiers abstract-declarator[opt]
|
2008-04-10 10:22:51 +08:00
|
|
|
/// '=' 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]"
|
2009-03-25 06:27:57 +08:00
|
|
|
/// and "exception-specification[opt]".
|
2008-10-25 05:46:40 +08:00
|
|
|
///
|
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
|
|
|
|
2009-08-20 07:14:54 +08:00
|
|
|
SourceLocation RParenLoc = ConsumeParen(); // Eat the closing ')'.
|
|
|
|
SourceLocation EndLoc = RParenLoc;
|
2008-10-25 05:46:40 +08:00
|
|
|
|
|
|
|
// cv-qualifier-seq[opt].
|
|
|
|
DeclSpec DS;
|
2009-04-30 01:30:04 +08:00
|
|
|
bool hasExceptionSpec = false;
|
2009-05-31 19:47:27 +08:00
|
|
|
SourceLocation ThrowLoc;
|
2009-04-30 01:30:04 +08:00
|
|
|
bool hasAnyExceptionSpec = false;
|
2009-05-30 02:02:33 +08:00
|
|
|
llvm::SmallVector<TypeTy*, 2> Exceptions;
|
|
|
|
llvm::SmallVector<SourceRange, 2> ExceptionRanges;
|
2008-10-25 05:46:40 +08:00
|
|
|
if (getLang().CPlusPlus) {
|
2008-12-18 15:02:59 +08:00
|
|
|
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
|
2009-02-10 02:23:29 +08:00
|
|
|
if (!DS.getSourceRange().getEnd().isInvalid())
|
2009-08-20 07:14:54 +08:00
|
|
|
EndLoc = DS.getSourceRange().getEnd();
|
2008-11-25 11:22:00 +08:00
|
|
|
|
|
|
|
// Parse exception-specification[opt].
|
2009-04-30 01:30:04 +08:00
|
|
|
if (Tok.is(tok::kw_throw)) {
|
|
|
|
hasExceptionSpec = true;
|
2009-05-31 19:47:27 +08:00
|
|
|
ThrowLoc = Tok.getLocation();
|
2009-08-20 07:14:54 +08:00
|
|
|
ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges,
|
2009-05-30 02:02:33 +08:00
|
|
|
hasAnyExceptionSpec);
|
|
|
|
assert(Exceptions.size() == ExceptionRanges.size() &&
|
|
|
|
"Produced different number of exception types and ranges.");
|
2009-04-30 01:30:04 +08:00
|
|
|
}
|
2008-10-25 05:46:40 +08:00
|
|
|
}
|
|
|
|
|
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,
|
2009-02-18 15:07:28 +08:00
|
|
|
SourceLocation(),
|
2008-10-25 05:46:40 +08:00
|
|
|
/*arglist*/ 0, 0,
|
|
|
|
DS.getTypeQualifiers(),
|
2009-05-31 19:47:27 +08:00
|
|
|
hasExceptionSpec, ThrowLoc,
|
2009-04-30 01:30:04 +08:00
|
|
|
hasAnyExceptionSpec,
|
2009-05-30 02:02:33 +08:00
|
|
|
Exceptions.data(),
|
|
|
|
ExceptionRanges.data(),
|
2009-04-30 01:30:04 +08:00
|
|
|
Exceptions.size(),
|
2009-08-20 07:14:54 +08:00
|
|
|
LParenLoc, RParenLoc, D),
|
|
|
|
EndLoc);
|
2008-04-06 14:57:35 +08:00
|
|
|
return;
|
2009-05-30 02:02:33 +08:00
|
|
|
}
|
|
|
|
|
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)
|
2009-01-29 03:16:40 +08:00
|
|
|
if (!getLang().CPlusPlus && Tok.is(tok::identifier)) {
|
2009-01-30 22:23:32 +08:00
|
|
|
if (!TryAnnotateTypeOrScopeToken()) {
|
2008-10-20 10:05:46 +08:00
|
|
|
// K&R identifier lists can't have typedefs as identifiers, per
|
|
|
|
// C99 6.7.5.3p11.
|
2009-01-29 03:16:40 +08:00
|
|
|
if (RequiresArg) {
|
|
|
|
Diag(Tok, diag::err_argument_required_after_attribute);
|
|
|
|
delete AttrList;
|
|
|
|
}
|
|
|
|
// Identifier list. Note that '(' identifier-list ')' is only allowed for
|
|
|
|
// normal declarators, not for abstract-declarators.
|
|
|
|
return ParseFunctionDeclaratorIdentifierList(LParenLoc, D);
|
2008-10-20 10:05:46 +08:00
|
|
|
}
|
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.
|
2009-03-05 08:00:31 +08:00
|
|
|
ParseScope PrototypeScope(this,
|
|
|
|
Scope::FunctionPrototypeScope|Scope::DeclScope);
|
2008-04-06 14:57:35 +08:00
|
|
|
|
|
|
|
bool IsVariadic = false;
|
2009-02-18 15:07:28 +08:00
|
|
|
SourceLocation EllipsisLoc;
|
2008-04-06 14:57:35 +08:00
|
|
|
while (1) {
|
|
|
|
if (Tok.is(tok::ellipsis)) {
|
|
|
|
IsVariadic = true;
|
2009-02-18 15:07:28 +08:00
|
|
|
EllipsisLoc = ConsumeToken(); // Consume the ellipsis.
|
2008-04-06 14:57:35 +08:00
|
|
|
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.
|
|
|
|
}
|
2009-02-28 02:38:20 +08:00
|
|
|
ParseDeclarationSpecifiers(DS);
|
|
|
|
|
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.
|
2009-02-10 02:23:29 +08:00
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
SourceLocation Loc;
|
|
|
|
AttributeList *AttrList = ParseAttributes(&Loc);
|
|
|
|
ParmDecl.AddAttributes(AttrList, Loc);
|
|
|
|
}
|
2008-04-06 14:57:35 +08:00
|
|
|
|
|
|
|
// Remember this parsed parameter in ParamInfo.
|
|
|
|
IdentifierInfo *ParmII = ParmDecl.getIdentifier();
|
|
|
|
|
2008-12-17 05:30:33 +08:00
|
|
|
// DefArgToks is used when the parsing of default arguments needs
|
|
|
|
// to be delayed.
|
|
|
|
CachedTokens *DefArgToks = 0;
|
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
// If no parameter was specified, verify that *something* was specified,
|
|
|
|
// otherwise we have a missing type and identifier.
|
2009-02-28 02:38:20 +08:00
|
|
|
if (DS.isEmpty() && ParmDecl.getIdentifier() == 0 &&
|
|
|
|
ParmDecl.getNumTypeObjects() == 0) {
|
2008-04-06 14:57:35 +08:00
|
|
|
// 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.
|
2009-03-29 03:18:32 +08:00
|
|
|
DeclPtrTy Param = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
|
2008-04-08 12:40:51 +08:00
|
|
|
|
|
|
|
// 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)) {
|
2008-12-24 08:01:03 +08:00
|
|
|
SourceLocation EqualLoc = Tok.getLocation();
|
|
|
|
|
2008-04-08 12:40:51 +08:00
|
|
|
// Parse the default argument
|
2008-12-17 05:30:33 +08:00
|
|
|
if (D.getContext() == Declarator::MemberContext) {
|
|
|
|
// If we're inside a class definition, cache the tokens
|
|
|
|
// corresponding to the default argument. We'll actually parse
|
|
|
|
// them when we see the end of the class definition.
|
|
|
|
// FIXME: Templates will require something similar.
|
|
|
|
// FIXME: Can we use a smart pointer for Toks?
|
|
|
|
DefArgToks = new CachedTokens;
|
|
|
|
|
|
|
|
if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks,
|
|
|
|
tok::semi, false)) {
|
|
|
|
delete DefArgToks;
|
|
|
|
DefArgToks = 0;
|
2008-12-24 08:01:03 +08:00
|
|
|
Actions.ActOnParamDefaultArgumentError(Param);
|
|
|
|
} else
|
2009-06-13 00:51:40 +08:00
|
|
|
Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc,
|
|
|
|
(*DefArgToks)[1].getLocation());
|
2008-04-08 12:40:51 +08:00
|
|
|
} else {
|
2008-12-17 05:30:33 +08:00
|
|
|
// Consume the '='.
|
2008-12-24 08:01:03 +08:00
|
|
|
ConsumeToken();
|
2008-12-17 05:30:33 +08:00
|
|
|
|
|
|
|
OwningExprResult DefArgResult(ParseAssignmentExpression());
|
|
|
|
if (DefArgResult.isInvalid()) {
|
|
|
|
Actions.ActOnParamDefaultArgumentError(Param);
|
|
|
|
SkipUntil(tok::comma, tok::r_paren, true, true);
|
|
|
|
} else {
|
|
|
|
// Inform the actions module about the default argument
|
|
|
|
Actions.ActOnParamDefaultArgument(Param, EqualLoc,
|
2009-03-16 01:47:39 +08:00
|
|
|
move(DefArgResult));
|
2008-12-17 05:30:33 +08:00
|
|
|
}
|
2008-04-08 12:40:51 +08:00
|
|
|
}
|
|
|
|
}
|
2006-08-07 01:24:14 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
|
2008-12-17 05:30:33 +08:00
|
|
|
ParmDecl.getIdentifierLoc(), Param,
|
|
|
|
DefArgToks));
|
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.
|
2008-12-10 14:34:36 +08:00
|
|
|
PrototypeScope.Exit();
|
2008-04-06 14:57:35 +08:00
|
|
|
|
2008-10-25 05:46:40 +08:00
|
|
|
// If we have the closing ')', eat it.
|
2009-08-20 07:14:54 +08:00
|
|
|
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
|
|
|
SourceLocation EndLoc = RParenLoc;
|
2008-10-25 05:46:40 +08:00
|
|
|
|
|
|
|
DeclSpec DS;
|
2009-04-30 01:30:04 +08:00
|
|
|
bool hasExceptionSpec = false;
|
2009-05-31 19:47:27 +08:00
|
|
|
SourceLocation ThrowLoc;
|
2009-04-30 01:30:04 +08:00
|
|
|
bool hasAnyExceptionSpec = false;
|
2009-05-30 02:02:33 +08:00
|
|
|
llvm::SmallVector<TypeTy*, 2> Exceptions;
|
|
|
|
llvm::SmallVector<SourceRange, 2> ExceptionRanges;
|
2008-10-25 05:46:40 +08:00
|
|
|
if (getLang().CPlusPlus) {
|
2008-11-25 11:22:00 +08:00
|
|
|
// Parse cv-qualifier-seq[opt].
|
2008-12-18 15:02:59 +08:00
|
|
|
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
|
2009-02-10 02:23:29 +08:00
|
|
|
if (!DS.getSourceRange().getEnd().isInvalid())
|
2009-08-20 07:14:54 +08:00
|
|
|
EndLoc = DS.getSourceRange().getEnd();
|
2008-11-25 11:22:00 +08:00
|
|
|
|
|
|
|
// Parse exception-specification[opt].
|
2009-04-30 01:30:04 +08:00
|
|
|
if (Tok.is(tok::kw_throw)) {
|
|
|
|
hasExceptionSpec = true;
|
2009-05-31 19:47:27 +08:00
|
|
|
ThrowLoc = Tok.getLocation();
|
2009-08-20 07:14:54 +08:00
|
|
|
ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges,
|
2009-05-30 02:02:33 +08:00
|
|
|
hasAnyExceptionSpec);
|
|
|
|
assert(Exceptions.size() == ExceptionRanges.size() &&
|
|
|
|
"Produced different number of exception types and ranges.");
|
2009-04-30 01:30:04 +08:00
|
|
|
}
|
2008-10-25 05:46:40 +08:00
|
|
|
}
|
|
|
|
|
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,
|
2009-02-18 15:07:28 +08:00
|
|
|
EllipsisLoc,
|
2009-05-21 17:52:38 +08:00
|
|
|
ParamInfo.data(), ParamInfo.size(),
|
2008-10-25 05:46:40 +08:00
|
|
|
DS.getTypeQualifiers(),
|
2009-05-31 19:47:27 +08:00
|
|
|
hasExceptionSpec, ThrowLoc,
|
2009-04-30 01:30:04 +08:00
|
|
|
hasAnyExceptionSpec,
|
2009-05-30 02:02:33 +08:00
|
|
|
Exceptions.data(),
|
|
|
|
ExceptionRanges.data(),
|
2009-08-20 07:14:54 +08:00
|
|
|
Exceptions.size(),
|
|
|
|
LParenLoc, RParenLoc, D),
|
|
|
|
EndLoc);
|
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(),
|
2009-03-29 03:18:32 +08:00
|
|
|
Tok.getLocation(),
|
|
|
|
DeclPtrTy()));
|
2008-04-06 14:34:08 +08:00
|
|
|
|
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.
|
2009-02-05 01:00:24 +08:00
|
|
|
if (Actions.getTypeName(*ParmII, Tok.getLocation(), 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,
|
2009-03-29 03:18:32 +08:00
|
|
|
Tok.getLocation(),
|
|
|
|
DeclPtrTy()));
|
2008-04-06 14:39:19 +08:00
|
|
|
}
|
2008-04-06 14:34:08 +08:00
|
|
|
|
|
|
|
// Eat the identifier.
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
2009-02-10 02:23:29 +08:00
|
|
|
|
|
|
|
// If we have the closing ')', eat it and we're done.
|
|
|
|
SourceLocation RLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
|
|
|
|
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,
|
2009-02-18 15:07:28 +08:00
|
|
|
SourceLocation(),
|
2008-04-06 14:39:19 +08:00
|
|
|
&ParamInfo[0], ParamInfo.size(),
|
2009-04-30 01:30:04 +08:00
|
|
|
/*TypeQuals*/0,
|
2009-05-31 19:47:27 +08:00
|
|
|
/*exception*/false,
|
|
|
|
SourceLocation(), false, 0, 0, 0,
|
2009-08-20 07:14:54 +08:00
|
|
|
LParenLoc, RLoc, D),
|
2009-02-10 02:23:29 +08:00
|
|
|
RLoc);
|
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
|
|
|
|
2008-12-18 15:27:21 +08:00
|
|
|
// C array syntax has many features, but by-far the most common is [] and [4].
|
|
|
|
// This code does a fast path to handle some of the most obvious cases.
|
|
|
|
if (Tok.getKind() == tok::r_square) {
|
2009-02-10 02:23:29 +08:00
|
|
|
SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
|
2008-12-18 15:27:21 +08:00
|
|
|
// Remember that we parsed the empty array type.
|
|
|
|
OwningExprResult NumElements(Actions);
|
2009-07-06 23:59:29 +08:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0,
|
|
|
|
StartLoc, EndLoc),
|
2009-02-10 02:23:29 +08:00
|
|
|
EndLoc);
|
2008-12-18 15:27:21 +08:00
|
|
|
return;
|
|
|
|
} else if (Tok.getKind() == tok::numeric_constant &&
|
|
|
|
GetLookAheadToken(1).is(tok::r_square)) {
|
|
|
|
// [4] is very common. Parse the numeric constant expression.
|
2009-01-19 02:53:16 +08:00
|
|
|
OwningExprResult ExprRes(Actions.ActOnNumericConstant(Tok));
|
2008-12-18 15:27:21 +08:00
|
|
|
ConsumeToken();
|
|
|
|
|
2009-02-10 02:23:29 +08:00
|
|
|
SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
|
2008-12-18 15:27:21 +08:00
|
|
|
|
|
|
|
// If there was an error parsing the assignment-expression, recover.
|
|
|
|
if (ExprRes.isInvalid())
|
|
|
|
ExprRes.release(); // Deallocate expr, just use [].
|
|
|
|
|
|
|
|
// Remember that we parsed a array type, and remember its features.
|
2009-07-06 23:59:29 +08:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0, ExprRes.release(),
|
|
|
|
StartLoc, EndLoc),
|
2009-02-10 02:23:29 +08:00
|
|
|
EndLoc);
|
2008-12-18 15:27:21 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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.
|
2008-12-18 14:50:14 +08:00
|
|
|
// Type qualifiers in an array subscript are a C99 feature.
|
2006-08-07 02:30:15 +08:00
|
|
|
DeclSpec DS;
|
2008-12-18 15:02:59 +08:00
|
|
|
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
|
2006-08-07 02:30:15 +08:00
|
|
|
|
|
|
|
// 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;
|
2008-12-10 04:22:58 +08:00
|
|
|
OwningExprResult NumElements(Actions);
|
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-12-18 14:50:14 +08:00
|
|
|
if (StaticLoc.isValid()) {
|
2008-04-06 13:26:30 +08:00
|
|
|
Diag(StaticLoc, diag::err_unspecified_vla_size_with_static);
|
2008-12-18 14:50:14 +08:00
|
|
|
StaticLoc = SourceLocation(); // Drop the static.
|
|
|
|
}
|
2008-04-06 13:26:30 +08:00
|
|
|
isStar = true;
|
2007-10-10 01:33:22 +08:00
|
|
|
} else if (Tok.isNot(tok::r_square)) {
|
2008-12-18 15:27:21 +08:00
|
|
|
// Note, in C89, this production uses the constant-expr production instead
|
|
|
|
// of assignment-expr. The only difference is that assignment-expr allows
|
|
|
|
// things like '=' and '*='. Sema rejects these in C89 mode because they
|
|
|
|
// are not i-c-e's, so we don't need to distinguish between the two here.
|
|
|
|
|
2009-06-20 07:52:42 +08:00
|
|
|
// Parse the constant-expression or assignment-expression now (depending
|
|
|
|
// on dialect).
|
|
|
|
if (getLang().CPlusPlus)
|
|
|
|
NumElements = ParseConstantExpression();
|
|
|
|
else
|
|
|
|
NumElements = ParseAssignmentExpression();
|
2006-08-13 02:40:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If there was an error parsing the assignment-expression, recover.
|
2008-12-09 21:15:23 +08:00
|
|
|
if (NumElements.isInvalid()) {
|
2009-04-25 06:30:50 +08:00
|
|
|
D.setInvalidType(true);
|
2006-08-13 02:40:58 +08:00
|
|
|
// If the expression was invalid, skip it.
|
|
|
|
SkipUntil(tok::r_square);
|
|
|
|
return;
|
2006-08-07 02:30:15 +08:00
|
|
|
}
|
2009-02-10 02:23:29 +08:00
|
|
|
|
|
|
|
SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
|
|
|
|
|
2008-12-18 15:27:21 +08:00
|
|
|
// Remember that we parsed a array type, and remember its features.
|
2006-12-02 14:43:02 +08:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
|
|
|
|
StaticLoc.isValid(), isStar,
|
2009-07-06 23:59:29 +08:00
|
|
|
NumElements.release(),
|
|
|
|
StartLoc, EndLoc),
|
2009-02-10 02:23:29 +08:00
|
|
|
EndLoc);
|
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");
|
2009-05-22 18:22:50 +08:00
|
|
|
Token OpTok = Tok;
|
2007-07-31 20:34:36 +08:00
|
|
|
SourceLocation StartLoc = ConsumeToken();
|
|
|
|
|
2009-05-22 18:22:50 +08:00
|
|
|
bool isCastExpr;
|
|
|
|
TypeTy *CastTy;
|
|
|
|
SourceRange CastRange;
|
|
|
|
OwningExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok,
|
|
|
|
isCastExpr,
|
|
|
|
CastTy,
|
|
|
|
CastRange);
|
|
|
|
|
|
|
|
if (CastRange.getEnd().isInvalid())
|
2008-09-05 19:26:19 +08:00
|
|
|
// FIXME: Not accurate, the range gets one token more than it should.
|
|
|
|
DS.SetRangeEnd(Tok.getLocation());
|
2009-05-22 18:22:50 +08:00
|
|
|
else
|
|
|
|
DS.SetRangeEnd(CastRange.getEnd());
|
|
|
|
|
|
|
|
if (isCastExpr) {
|
|
|
|
if (!CastTy) {
|
|
|
|
DS.SetTypeSpecError();
|
2007-08-02 10:53:48 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-05-22 18:22:18 +08:00
|
|
|
|
2009-05-22 18:22:50 +08:00
|
|
|
const char *PrevSpec = 0;
|
2009-08-04 04:12:06 +08:00
|
|
|
unsigned DiagID;
|
2009-05-22 18:22:50 +08:00
|
|
|
// Check for duplicate type specifiers (e.g. "int typeof(int)").
|
|
|
|
if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec,
|
2009-08-04 04:12:06 +08:00
|
|
|
DiagID, CastTy))
|
|
|
|
Diag(StartLoc, DiagID) << PrevSpec;
|
2009-05-22 18:22:50 +08:00
|
|
|
return;
|
2007-07-31 20:34:36 +08:00
|
|
|
}
|
|
|
|
|
2009-05-22 18:22:18 +08:00
|
|
|
// If we get here, the operand to the typeof was an expresion.
|
|
|
|
if (Operand.isInvalid()) {
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
return;
|
|
|
|
}
|
2008-05-10 07:39:43 +08:00
|
|
|
|
2009-05-22 18:22:18 +08:00
|
|
|
const char *PrevSpec = 0;
|
2009-08-04 04:12:06 +08:00
|
|
|
unsigned DiagID;
|
2009-05-22 18:22:18 +08:00
|
|
|
// Check for duplicate type specifiers (e.g. "int typeof(int)").
|
|
|
|
if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec,
|
2009-08-04 04:12:06 +08:00
|
|
|
DiagID, Operand.release()))
|
|
|
|
Diag(StartLoc, DiagID) << PrevSpec;
|
2009-05-22 18:22:18 +08:00
|
|
|
}
|