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"
|
2011-03-19 06:38:29 +08:00
|
|
|
#include "clang/Basic/OpenCL.h"
|
2012-04-27 07:36:17 +08:00
|
|
|
#include "clang/Sema/Lookup.h"
|
2010-08-21 02:27:03 +08:00
|
|
|
#include "clang/Sema/Scope.h"
|
|
|
|
#include "clang/Sema/ParsedTemplate.h"
|
2010-08-27 07:41:50 +08:00
|
|
|
#include "clang/Sema/PrettyDeclStackTrace.h"
|
2009-12-10 08:21:05 +08:00
|
|
|
#include "RAIIObjectsForParser.h"
|
2007-01-23 09:14:52 +08:00
|
|
|
#include "llvm/ADT/SmallSet.h"
|
2012-02-04 21:45:25 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2011-08-10 01:59:31 +08:00
|
|
|
#include "llvm/ADT/StringSwitch.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++.
|
2011-02-01 00:09:46 +08:00
|
|
|
TypeResult Parser::ParseTypeName(SourceRange *Range,
|
2011-06-16 07:02:42 +08:00
|
|
|
Declarator::TheContext Context,
|
2011-07-02 03:46:12 +08:00
|
|
|
AccessSpecifier AS,
|
|
|
|
Decl **OwnedType) {
|
2012-03-15 09:02:11 +08:00
|
|
|
DeclSpecContext DSC = getDeclSpecContextFromDeclaratorContext(Context);
|
2012-05-10 04:55:26 +08:00
|
|
|
if (DSC == DSC_normal)
|
|
|
|
DSC = DSC_type_specifier;
|
2012-03-12 16:56:40 +08:00
|
|
|
|
2006-08-11 07:56:11 +08:00
|
|
|
// Parse the common declaration-specifiers piece.
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2012-03-12 16:56:40 +08:00
|
|
|
ParseSpecifierQualifierList(DS, AS, DSC);
|
2011-07-02 03:46:12 +08:00
|
|
|
if (OwnedType)
|
|
|
|
*OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0;
|
2009-05-30 02:02:33 +08:00
|
|
|
|
2006-08-11 07:56:11 +08:00
|
|
|
// Parse the abstract-declarator, if present.
|
2011-02-01 00:09:46 +08:00
|
|
|
Declarator DeclaratorInfo(DS, Context);
|
2006-08-11 07:56:11 +08:00
|
|
|
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;
|
|
|
|
|
2010-07-03 01:43:08 +08:00
|
|
|
return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
2006-08-11 07:56:11 +08:00
|
|
|
}
|
|
|
|
|
2011-09-09 01:42:22 +08:00
|
|
|
|
|
|
|
/// isAttributeLateParsed - Return true if the attribute has arguments that
|
|
|
|
/// require late parsing.
|
|
|
|
static bool isAttributeLateParsed(const IdentifierInfo &II) {
|
|
|
|
return llvm::StringSwitch<bool>(II.getName())
|
|
|
|
#include "clang/Parse/AttrLateParsed.inc"
|
|
|
|
.Default(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
/// ParseGNUAttributes - Parse a non-empty attributes list.
|
2006-08-15 12:10:46 +08:00
|
|
|
///
|
|
|
|
/// [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
|
2009-09-09 23:08:12 +08:00
|
|
|
///
|
2007-06-02 01:11:19 +08:00
|
|
|
/// FIXME: The GCC grammar/code for this construct implies we need two
|
2009-09-09 23:08:12 +08:00
|
|
|
/// token lookahead. Comment from gcc: "If they start with an identifier
|
|
|
|
/// which is followed by a comma or close parenthesis, then the arguments
|
2007-06-02 01:11:19 +08:00
|
|
|
/// start with that identifier; otherwise they are an expression list."
|
|
|
|
///
|
2011-10-18 05:20:17 +08:00
|
|
|
/// GCC does not require the ',' between attribs in an attribute-list.
|
|
|
|
///
|
2007-06-02 01:11:19 +08:00
|
|
|
/// 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.
|
|
|
|
|
2010-12-24 10:08:15 +08:00
|
|
|
void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
|
2011-09-09 01:42:22 +08:00
|
|
|
SourceLocation *endLoc,
|
|
|
|
LateParsedAttrList *LateAttrs) {
|
2009-11-21 16:43:09 +08:00
|
|
|
assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!");
|
2009-09-09 23:08:12 +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 ;
|
2010-12-24 10:08:15 +08:00
|
|
|
return;
|
2007-06-02 01:11:19 +08:00
|
|
|
}
|
|
|
|
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) {
|
|
|
|
SkipUntil(tok::r_paren, true); // skip until ) or ;
|
2010-12-24 10:08:15 +08:00
|
|
|
return;
|
2007-06-02 01:11:19 +08:00
|
|
|
}
|
|
|
|
// 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)) {
|
2009-09-09 23:08:12 +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();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-09-09 01:42:22 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
// handle "parameterized" attributes
|
2012-02-17 00:50:43 +08:00
|
|
|
if (LateAttrs && isAttributeLateParsed(*AttrName)) {
|
2011-09-09 01:42:22 +08:00
|
|
|
LateParsedAttribute *LA =
|
|
|
|
new LateParsedAttribute(this, *AttrName, AttrNameLoc);
|
|
|
|
LateAttrs->push_back(LA);
|
2012-02-17 00:50:43 +08:00
|
|
|
|
|
|
|
// Attributes in a class are parsed at the end of the class, along
|
|
|
|
// with other late-parsed declarations.
|
|
|
|
if (!ClassStack.empty())
|
|
|
|
getCurrentClass().LateParsedDeclarations.push_back(LA);
|
2011-09-09 01:42:22 +08:00
|
|
|
|
|
|
|
// consume everything up to and including the matching right parens
|
|
|
|
ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false);
|
|
|
|
|
|
|
|
Token Eof;
|
|
|
|
Eof.startToken();
|
|
|
|
Eof.setLocation(Tok.getLocation());
|
|
|
|
LA->Toks.push_back(Eof);
|
|
|
|
} else {
|
|
|
|
ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc);
|
2007-06-02 01:11:19 +08:00
|
|
|
}
|
|
|
|
} else {
|
2011-03-24 19:26:52 +08:00
|
|
|
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
|
|
|
|
0, SourceLocation(), 0, 0);
|
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-11-21 16:43:09 +08:00
|
|
|
SourceLocation Loc = Tok.getLocation();
|
2009-02-10 02:23:29 +08:00
|
|
|
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
|
|
|
|
SkipUntil(tok::r_paren, false);
|
|
|
|
}
|
2010-12-24 10:08:15 +08:00
|
|
|
if (endLoc)
|
|
|
|
*endLoc = Loc;
|
2007-06-02 01:11:19 +08:00
|
|
|
}
|
2006-08-15 12:10:46 +08:00
|
|
|
}
|
|
|
|
|
2011-09-09 01:42:22 +08:00
|
|
|
|
|
|
|
/// Parse the arguments to a parameterized GNU attribute
|
|
|
|
void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
|
|
|
|
SourceLocation AttrNameLoc,
|
|
|
|
ParsedAttributes &Attrs,
|
|
|
|
SourceLocation *EndLoc) {
|
|
|
|
|
|
|
|
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
|
|
|
|
|
|
|
|
// Availability attributes have their own grammar.
|
|
|
|
if (AttrName->isStr("availability")) {
|
|
|
|
ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Thread safety attributes fit into the FIXME case above, so we
|
|
|
|
// just parse the arguments as a list of expressions
|
|
|
|
if (IsThreadSafetyAttribute(AttrName->getName())) {
|
|
|
|
ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConsumeParen(); // ignore the left paren loc for now
|
|
|
|
|
2011-10-18 05:20:17 +08:00
|
|
|
IdentifierInfo *ParmName = 0;
|
|
|
|
SourceLocation ParmLoc;
|
|
|
|
bool BuiltinType = false;
|
2011-09-09 01:42:22 +08:00
|
|
|
|
2011-10-18 05:20:17 +08:00
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::kw_char:
|
|
|
|
case tok::kw_wchar_t:
|
|
|
|
case tok::kw_char16_t:
|
|
|
|
case tok::kw_char32_t:
|
|
|
|
case tok::kw_bool:
|
|
|
|
case tok::kw_short:
|
|
|
|
case tok::kw_int:
|
|
|
|
case tok::kw_long:
|
|
|
|
case tok::kw___int64:
|
2012-04-04 14:24:32 +08:00
|
|
|
case tok::kw___int128:
|
2011-10-18 05:20:17 +08:00
|
|
|
case tok::kw_signed:
|
|
|
|
case tok::kw_unsigned:
|
|
|
|
case tok::kw_float:
|
|
|
|
case tok::kw_double:
|
|
|
|
case tok::kw_void:
|
|
|
|
case tok::kw_typeof:
|
|
|
|
// __attribute__(( vec_type_hint(char) ))
|
|
|
|
// FIXME: Don't just discard the builtin type token.
|
|
|
|
ConsumeToken();
|
|
|
|
BuiltinType = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::identifier:
|
|
|
|
ParmName = Tok.getIdentifierInfo();
|
|
|
|
ParmLoc = ConsumeToken();
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ExprVector ArgExprs(Actions);
|
|
|
|
|
|
|
|
if (!BuiltinType &&
|
|
|
|
(ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) {
|
|
|
|
// Eat the comma.
|
|
|
|
if (ParmLoc.isValid())
|
2011-09-09 01:42:22 +08:00
|
|
|
ConsumeToken();
|
|
|
|
|
2011-10-18 05:20:17 +08:00
|
|
|
// Parse the non-empty comma-separated list of expressions.
|
|
|
|
while (1) {
|
|
|
|
ExprResult ArgExpr(ParseAssignmentExpression());
|
|
|
|
if (ArgExpr.isInvalid()) {
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
2011-09-09 01:42:22 +08:00
|
|
|
}
|
2011-10-18 05:20:17 +08:00
|
|
|
ArgExprs.push_back(ArgExpr.release());
|
|
|
|
if (Tok.isNot(tok::comma))
|
|
|
|
break;
|
|
|
|
ConsumeToken(); // Eat the comma, move to the next argument
|
2011-09-09 01:42:22 +08:00
|
|
|
}
|
2011-10-18 05:20:17 +08:00
|
|
|
}
|
2011-10-19 01:11:10 +08:00
|
|
|
else if (Tok.is(tok::less) && AttrName->isStr("iboutletcollection")) {
|
|
|
|
if (!ExpectAndConsume(tok::less, diag::err_expected_less_after, "<",
|
|
|
|
tok::greater)) {
|
2011-10-19 07:13:50 +08:00
|
|
|
while (Tok.is(tok::identifier)) {
|
|
|
|
ConsumeToken();
|
|
|
|
if (Tok.is(tok::greater))
|
|
|
|
break;
|
|
|
|
if (Tok.is(tok::comma)) {
|
|
|
|
ConsumeToken();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Tok.isNot(tok::greater))
|
|
|
|
Diag(Tok, diag::err_iboutletcollection_with_protocol);
|
2011-10-19 01:11:10 +08:00
|
|
|
SkipUntil(tok::r_paren, false, true); // skip until ')'
|
|
|
|
}
|
|
|
|
}
|
2011-09-09 01:42:22 +08:00
|
|
|
|
2011-10-18 05:20:17 +08:00
|
|
|
SourceLocation RParen = Tok.getLocation();
|
|
|
|
if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
|
|
|
|
AttributeList *attr =
|
|
|
|
Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc,
|
|
|
|
ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size());
|
2012-03-07 08:12:16 +08:00
|
|
|
if (BuiltinType && attr->getKind() == AttributeList::AT_iboutletcollection)
|
2011-10-18 05:20:17 +08:00
|
|
|
Diag(Tok, diag::err_iboutletcollection_builtintype);
|
2011-09-09 01:42:22 +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
|
|
|
|
|
2010-12-24 10:08:15 +08:00
|
|
|
void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) {
|
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 ;
|
2010-12-24 10:08:15 +08:00
|
|
|
return;
|
2009-06-08 15:21:15 +08:00
|
|
|
}
|
2011-05-08 03:04:49 +08:00
|
|
|
|
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();
|
2011-05-08 03:04:49 +08:00
|
|
|
|
|
|
|
// FIXME: Remove this when we have proper __declspec(property()) support.
|
|
|
|
// Just skip everything inside property().
|
|
|
|
if (AttrName->getName() == "property") {
|
|
|
|
ConsumeParen();
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
}
|
2009-06-08 15:21:15 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
ConsumeParen();
|
|
|
|
// FIXME: This doesn't parse __declspec(property(get=get_func_name))
|
|
|
|
// correctly.
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult ArgExpr(ParseAssignmentExpression());
|
2009-06-08 15:21:15 +08:00
|
|
|
if (!ArgExpr.isInvalid()) {
|
2010-08-23 14:44:23 +08:00
|
|
|
Expr *ExprList = ArgExpr.take();
|
2011-03-24 19:26:52 +08:00
|
|
|
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
|
|
|
|
SourceLocation(), &ExprList, 1, true);
|
2009-06-08 15:21:15 +08:00
|
|
|
}
|
|
|
|
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
|
|
|
|
SkipUntil(tok::r_paren, false);
|
|
|
|
} else {
|
2011-03-24 19:26:52 +08:00
|
|
|
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
|
|
|
|
0, SourceLocation(), 0, 0, true);
|
2009-06-08 15:21:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
|
|
|
|
SkipUntil(tok::r_paren, false);
|
2010-12-24 10:08:15 +08:00
|
|
|
return;
|
2009-06-09 07:27:34 +08:00
|
|
|
}
|
|
|
|
|
2010-12-24 10:08:15 +08:00
|
|
|
void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
|
2009-06-09 07:27:34 +08:00
|
|
|
// 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) ||
|
2010-05-19 00:57:00 +08:00
|
|
|
Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) ||
|
2011-08-18 17:59:55 +08:00
|
|
|
Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) ||
|
2011-08-25 08:36:46 +08:00
|
|
|
Tok.is(tok::kw___ptr32) ||
|
2011-08-18 17:59:55 +08:00
|
|
|
Tok.is(tok::kw___unaligned)) {
|
2009-06-09 07:27:34 +08:00
|
|
|
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation AttrNameLoc = ConsumeToken();
|
2011-03-24 19:26:52 +08:00
|
|
|
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
|
|
|
|
SourceLocation(), 0, 0, true);
|
2009-06-09 07:27:34 +08:00
|
|
|
}
|
2008-12-25 04:59:21 +08:00
|
|
|
}
|
|
|
|
|
2010-12-24 10:08:15 +08:00
|
|
|
void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) {
|
2010-09-03 09:29:35 +08:00
|
|
|
// Treat these like attributes
|
|
|
|
while (Tok.is(tok::kw___pascal)) {
|
|
|
|
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation AttrNameLoc = ConsumeToken();
|
2011-03-24 19:26:52 +08:00
|
|
|
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
|
|
|
|
SourceLocation(), 0, 0, true);
|
2010-09-03 09:29:35 +08:00
|
|
|
}
|
2010-12-24 10:08:15 +08:00
|
|
|
}
|
|
|
|
|
2011-02-14 09:42:53 +08:00
|
|
|
void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) {
|
|
|
|
// Treat these like attributes
|
|
|
|
while (Tok.is(tok::kw___kernel)) {
|
|
|
|
SourceLocation AttrNameLoc = ConsumeToken();
|
2011-03-24 19:26:52 +08:00
|
|
|
attrs.addNew(PP.getIdentifierInfo("opencl_kernel_function"),
|
|
|
|
AttrNameLoc, 0, AttrNameLoc, 0,
|
|
|
|
SourceLocation(), 0, 0, false);
|
2011-02-14 09:42:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-19 06:38:29 +08:00
|
|
|
void Parser::ParseOpenCLQualifiers(DeclSpec &DS) {
|
|
|
|
SourceLocation Loc = Tok.getLocation();
|
|
|
|
switch(Tok.getKind()) {
|
|
|
|
// OpenCL qualifiers:
|
|
|
|
case tok::kw___private:
|
|
|
|
case tok::kw_private:
|
2011-03-24 19:26:52 +08:00
|
|
|
DS.getAttributes().addNewInteger(
|
2011-03-19 06:38:29 +08:00
|
|
|
Actions.getASTContext(),
|
2011-03-24 19:26:52 +08:00
|
|
|
PP.getIdentifierInfo("address_space"), Loc, 0);
|
2011-03-19 06:38:29 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::kw___global:
|
2011-03-24 19:26:52 +08:00
|
|
|
DS.getAttributes().addNewInteger(
|
2011-03-19 06:38:29 +08:00
|
|
|
Actions.getASTContext(),
|
2011-03-24 19:26:52 +08:00
|
|
|
PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_global);
|
2011-03-19 06:38:29 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::kw___local:
|
2011-03-24 19:26:52 +08:00
|
|
|
DS.getAttributes().addNewInteger(
|
2011-03-19 06:38:29 +08:00
|
|
|
Actions.getASTContext(),
|
2011-03-24 19:26:52 +08:00
|
|
|
PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_local);
|
2011-03-19 06:38:29 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::kw___constant:
|
2011-03-24 19:26:52 +08:00
|
|
|
DS.getAttributes().addNewInteger(
|
2011-03-19 06:38:29 +08:00
|
|
|
Actions.getASTContext(),
|
2011-03-24 19:26:52 +08:00
|
|
|
PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_constant);
|
2011-03-19 06:38:29 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::kw___read_only:
|
2011-03-24 19:26:52 +08:00
|
|
|
DS.getAttributes().addNewInteger(
|
2011-03-19 06:38:29 +08:00
|
|
|
Actions.getASTContext(),
|
2011-03-24 19:26:52 +08:00
|
|
|
PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_only);
|
2011-03-19 06:38:29 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::kw___write_only:
|
2011-03-24 19:26:52 +08:00
|
|
|
DS.getAttributes().addNewInteger(
|
2011-03-19 06:38:29 +08:00
|
|
|
Actions.getASTContext(),
|
2011-03-24 19:26:52 +08:00
|
|
|
PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_write_only);
|
2011-03-19 06:38:29 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::kw___read_write:
|
2011-03-24 19:26:52 +08:00
|
|
|
DS.getAttributes().addNewInteger(
|
2011-03-19 06:38:29 +08:00
|
|
|
Actions.getASTContext(),
|
2011-03-24 19:26:52 +08:00
|
|
|
PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_write);
|
2011-03-19 06:38:29 +08:00
|
|
|
break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
/// \brief Parse a version number.
|
|
|
|
///
|
|
|
|
/// version:
|
|
|
|
/// simple-integer
|
|
|
|
/// simple-integer ',' simple-integer
|
|
|
|
/// simple-integer ',' simple-integer ',' simple-integer
|
|
|
|
VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
|
|
|
|
Range = Tok.getLocation();
|
|
|
|
|
|
|
|
if (!Tok.is(tok::numeric_constant)) {
|
|
|
|
Diag(Tok, diag::err_expected_version);
|
|
|
|
SkipUntil(tok::comma, tok::r_paren, true, true, true);
|
|
|
|
return VersionTuple();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the major (and possibly minor and subminor) versions, which
|
|
|
|
// are stored in the numeric constant. We utilize a quirk of the
|
|
|
|
// lexer, which is that it handles something like 1.2.3 as a single
|
|
|
|
// numeric constant, rather than two separate tokens.
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<512> Buffer;
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
Buffer.resize(Tok.getLength()+1);
|
|
|
|
const char *ThisTokBegin = &Buffer[0];
|
|
|
|
|
|
|
|
// Get the spelling of the token, which eliminates trigraphs, etc.
|
|
|
|
bool Invalid = false;
|
|
|
|
unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin, &Invalid);
|
|
|
|
if (Invalid)
|
|
|
|
return VersionTuple();
|
|
|
|
|
|
|
|
// Parse the major version.
|
|
|
|
unsigned AfterMajor = 0;
|
|
|
|
unsigned Major = 0;
|
|
|
|
while (AfterMajor < ActualLength && isdigit(ThisTokBegin[AfterMajor])) {
|
|
|
|
Major = Major * 10 + ThisTokBegin[AfterMajor] - '0';
|
|
|
|
++AfterMajor;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (AfterMajor == 0) {
|
|
|
|
Diag(Tok, diag::err_expected_version);
|
|
|
|
SkipUntil(tok::comma, tok::r_paren, true, true, true);
|
|
|
|
return VersionTuple();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (AfterMajor == ActualLength) {
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// We only had a single version component.
|
|
|
|
if (Major == 0) {
|
|
|
|
Diag(Tok, diag::err_zero_version);
|
|
|
|
return VersionTuple();
|
|
|
|
}
|
|
|
|
|
|
|
|
return VersionTuple(Major);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ThisTokBegin[AfterMajor] != '.' || (AfterMajor + 1 == ActualLength)) {
|
|
|
|
Diag(Tok, diag::err_expected_version);
|
|
|
|
SkipUntil(tok::comma, tok::r_paren, true, true, true);
|
|
|
|
return VersionTuple();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the minor version.
|
|
|
|
unsigned AfterMinor = AfterMajor + 1;
|
|
|
|
unsigned Minor = 0;
|
|
|
|
while (AfterMinor < ActualLength && isdigit(ThisTokBegin[AfterMinor])) {
|
|
|
|
Minor = Minor * 10 + ThisTokBegin[AfterMinor] - '0';
|
|
|
|
++AfterMinor;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (AfterMinor == ActualLength) {
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// We had major.minor.
|
|
|
|
if (Major == 0 && Minor == 0) {
|
|
|
|
Diag(Tok, diag::err_zero_version);
|
|
|
|
return VersionTuple();
|
|
|
|
}
|
|
|
|
|
|
|
|
return VersionTuple(Major, Minor);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If what follows is not a '.', we have a problem.
|
|
|
|
if (ThisTokBegin[AfterMinor] != '.') {
|
|
|
|
Diag(Tok, diag::err_expected_version);
|
|
|
|
SkipUntil(tok::comma, tok::r_paren, true, true, true);
|
|
|
|
return VersionTuple();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the subminor version.
|
|
|
|
unsigned AfterSubminor = AfterMinor + 1;
|
|
|
|
unsigned Subminor = 0;
|
|
|
|
while (AfterSubminor < ActualLength && isdigit(ThisTokBegin[AfterSubminor])) {
|
|
|
|
Subminor = Subminor * 10 + ThisTokBegin[AfterSubminor] - '0';
|
|
|
|
++AfterSubminor;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (AfterSubminor != ActualLength) {
|
|
|
|
Diag(Tok, diag::err_expected_version);
|
|
|
|
SkipUntil(tok::comma, tok::r_paren, true, true, true);
|
|
|
|
return VersionTuple();
|
|
|
|
}
|
|
|
|
ConsumeToken();
|
|
|
|
return VersionTuple(Major, Minor, Subminor);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Parse the contents of the "availability" attribute.
|
|
|
|
///
|
|
|
|
/// availability-attribute:
|
2011-12-10 08:28:41 +08:00
|
|
|
/// 'availability' '(' platform ',' version-arg-list, opt-message')'
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
///
|
|
|
|
/// platform:
|
|
|
|
/// identifier
|
|
|
|
///
|
|
|
|
/// version-arg-list:
|
|
|
|
/// version-arg
|
|
|
|
/// version-arg ',' version-arg-list
|
|
|
|
///
|
|
|
|
/// version-arg:
|
|
|
|
/// 'introduced' '=' version
|
|
|
|
/// 'deprecated' '=' version
|
2012-03-11 12:53:21 +08:00
|
|
|
/// 'obsoleted' = version
|
2011-03-26 11:35:55 +08:00
|
|
|
/// 'unavailable'
|
2011-12-10 08:28:41 +08:00
|
|
|
/// opt-message:
|
|
|
|
/// 'message' '=' <string>
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
|
|
|
|
SourceLocation AvailabilityLoc,
|
|
|
|
ParsedAttributes &attrs,
|
|
|
|
SourceLocation *endLoc) {
|
|
|
|
SourceLocation PlatformLoc;
|
|
|
|
IdentifierInfo *Platform = 0;
|
|
|
|
|
|
|
|
enum { Introduced, Deprecated, Obsoleted, Unknown };
|
|
|
|
AvailabilityChange Changes[Unknown];
|
2011-12-10 08:28:41 +08:00
|
|
|
ExprResult MessageExpr;
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
|
|
|
|
// Opening '('.
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
if (T.consumeOpen()) {
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the platform name,
|
|
|
|
if (Tok.isNot(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_availability_expected_platform);
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Platform = Tok.getIdentifierInfo();
|
|
|
|
PlatformLoc = ConsumeToken();
|
|
|
|
|
|
|
|
// Parse the ',' following the platform name.
|
|
|
|
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::r_paren))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// If we haven't grabbed the pointers for the identifiers
|
|
|
|
// "introduced", "deprecated", and "obsoleted", do so now.
|
|
|
|
if (!Ident_introduced) {
|
|
|
|
Ident_introduced = PP.getIdentifierInfo("introduced");
|
|
|
|
Ident_deprecated = PP.getIdentifierInfo("deprecated");
|
|
|
|
Ident_obsoleted = PP.getIdentifierInfo("obsoleted");
|
2011-03-26 11:35:55 +08:00
|
|
|
Ident_unavailable = PP.getIdentifierInfo("unavailable");
|
2011-12-10 08:28:41 +08:00
|
|
|
Ident_message = PP.getIdentifierInfo("message");
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the set of introductions/deprecations/removals.
|
2011-03-26 11:35:55 +08:00
|
|
|
SourceLocation UnavailableLoc;
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
do {
|
|
|
|
if (Tok.isNot(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_availability_expected_change);
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
IdentifierInfo *Keyword = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation KeywordLoc = ConsumeToken();
|
|
|
|
|
2011-03-26 11:35:55 +08:00
|
|
|
if (Keyword == Ident_unavailable) {
|
|
|
|
if (UnavailableLoc.isValid()) {
|
|
|
|
Diag(KeywordLoc, diag::err_availability_redundant)
|
|
|
|
<< Keyword << SourceRange(UnavailableLoc);
|
|
|
|
}
|
|
|
|
UnavailableLoc = KeywordLoc;
|
|
|
|
|
|
|
|
if (Tok.isNot(tok::comma))
|
|
|
|
break;
|
|
|
|
|
|
|
|
ConsumeToken();
|
|
|
|
continue;
|
|
|
|
}
|
2011-12-10 08:28:41 +08:00
|
|
|
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
if (Tok.isNot(tok::equal)) {
|
|
|
|
Diag(Tok, diag::err_expected_equal_after)
|
|
|
|
<< Keyword;
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ConsumeToken();
|
2011-12-10 08:28:41 +08:00
|
|
|
if (Keyword == Ident_message) {
|
|
|
|
if (!isTokenStringLiteral()) {
|
|
|
|
Diag(Tok, diag::err_expected_string_literal);
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
MessageExpr = ParseStringLiteralExpression();
|
|
|
|
break;
|
|
|
|
}
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
|
|
|
|
SourceRange VersionRange;
|
|
|
|
VersionTuple Version = ParseVersionTuple(VersionRange);
|
|
|
|
|
|
|
|
if (Version.empty()) {
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Index;
|
|
|
|
if (Keyword == Ident_introduced)
|
|
|
|
Index = Introduced;
|
|
|
|
else if (Keyword == Ident_deprecated)
|
|
|
|
Index = Deprecated;
|
|
|
|
else if (Keyword == Ident_obsoleted)
|
|
|
|
Index = Obsoleted;
|
|
|
|
else
|
|
|
|
Index = Unknown;
|
|
|
|
|
|
|
|
if (Index < Unknown) {
|
|
|
|
if (!Changes[Index].KeywordLoc.isInvalid()) {
|
|
|
|
Diag(KeywordLoc, diag::err_availability_redundant)
|
|
|
|
<< Keyword
|
|
|
|
<< SourceRange(Changes[Index].KeywordLoc,
|
|
|
|
Changes[Index].VersionRange.getEnd());
|
|
|
|
}
|
|
|
|
|
|
|
|
Changes[Index].KeywordLoc = KeywordLoc;
|
|
|
|
Changes[Index].Version = Version;
|
|
|
|
Changes[Index].VersionRange = VersionRange;
|
|
|
|
} else {
|
|
|
|
Diag(KeywordLoc, diag::err_availability_unknown_change)
|
|
|
|
<< Keyword << VersionRange;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Tok.isNot(tok::comma))
|
|
|
|
break;
|
|
|
|
|
|
|
|
ConsumeToken();
|
|
|
|
} while (true);
|
|
|
|
|
|
|
|
// Closing ')'.
|
2011-10-13 00:37:45 +08:00
|
|
|
if (T.consumeClose())
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (endLoc)
|
2011-10-13 00:37:45 +08:00
|
|
|
*endLoc = T.getCloseLocation();
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
|
2011-03-26 11:35:55 +08:00
|
|
|
// The 'unavailable' availability cannot be combined with any other
|
|
|
|
// availability changes. Make sure that hasn't happened.
|
|
|
|
if (UnavailableLoc.isValid()) {
|
|
|
|
bool Complained = false;
|
|
|
|
for (unsigned Index = Introduced; Index != Unknown; ++Index) {
|
|
|
|
if (Changes[Index].KeywordLoc.isValid()) {
|
|
|
|
if (!Complained) {
|
|
|
|
Diag(UnavailableLoc, diag::warn_availability_and_unavailable)
|
|
|
|
<< SourceRange(Changes[Index].KeywordLoc,
|
|
|
|
Changes[Index].VersionRange.getEnd());
|
|
|
|
Complained = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear out the availability.
|
|
|
|
Changes[Index] = AvailabilityChange();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
// Record this attribute
|
2011-10-13 00:37:45 +08:00
|
|
|
attrs.addNew(&Availability,
|
|
|
|
SourceRange(AvailabilityLoc, T.getCloseLocation()),
|
2012-01-24 07:38:32 +08:00
|
|
|
0, AvailabilityLoc,
|
2011-03-24 19:26:52 +08:00
|
|
|
Platform, PlatformLoc,
|
|
|
|
Changes[Introduced],
|
|
|
|
Changes[Deprecated],
|
2011-03-26 11:35:55 +08:00
|
|
|
Changes[Obsoleted],
|
2011-12-10 08:28:41 +08:00
|
|
|
UnavailableLoc, MessageExpr.take(),
|
|
|
|
false, false);
|
Implement a new 'availability' attribute, that allows one to specify
which versions of an OS provide a certain facility. For example,
void foo()
__attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
says that the function "foo" was introduced in 10.2, deprecated in
10.4, and completely obsoleted in 10.6. This attribute ties in with
the deployment targets (e.g., -mmacosx-version-min=10.1 specifies that
we want to deploy back to Mac OS X 10.1). There are several concrete
behaviors that this attribute enables, as illustrated with the
function foo() above:
- If we choose a deployment target >= Mac OS X 10.4, uses of "foo"
will result in a deprecation warning, as if we had placed
attribute((deprecated)) on it (but with a better diagnostic)
- If we choose a deployment target >= Mac OS X 10.6, uses of "foo"
will result in an "unavailable" warning (in C)/error (in C++), as
if we had placed attribute((unavailable)) on it
- If we choose a deployment target prior to 10.2, foo() is
weak-imported (if it is a kind of entity that can be weak
imported), as if we had placed the weak_import attribute on it.
Naturally, there can be multiple availability attributes on a
declaration, for different platforms; only the current platform
matters when checking availability attributes.
The only platforms this attribute currently works for are "ios" and
"macosx", since we already have -mxxxx-version-min flags for them and we
have experience there with macro tricks translating down to the
deprecated/unavailable/weak_import attributes. The end goal is to open
this up to other platforms, and even extension to other "platforms"
that are really libraries (say, through a #pragma clang
define_system), but that hasn't yet been designed and we may want to
shake out more issues with this narrower problem first.
Addresses <rdar://problem/6690412>.
As a drive-by bug-fix, if an entity is both deprecated and
unavailable, we only emit the "unavailable" diagnostic.
llvm-svn: 128127
2011-03-23 08:50:03 +08:00
|
|
|
}
|
|
|
|
|
2011-09-09 01:42:22 +08:00
|
|
|
|
|
|
|
// Late Parsed Attributes:
|
|
|
|
// See other examples of late parsing in lib/Parse/ParseCXXInlineMethods
|
|
|
|
|
|
|
|
void Parser::LateParsedDeclaration::ParseLexedAttributes() {}
|
|
|
|
|
|
|
|
void Parser::LateParsedClass::ParseLexedAttributes() {
|
|
|
|
Self->ParseLexedAttributes(*Class);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Parser::LateParsedAttribute::ParseLexedAttributes() {
|
2012-02-17 00:50:43 +08:00
|
|
|
Self->ParseLexedAttribute(*this, true, false);
|
2011-09-09 01:42:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Wrapper class which calls ParseLexedAttribute, after setting up the
|
|
|
|
/// scope appropriately.
|
|
|
|
void Parser::ParseLexedAttributes(ParsingClass &Class) {
|
|
|
|
// Deal with templates
|
|
|
|
// FIXME: Test cases to make sure this does the right thing for templates.
|
|
|
|
bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
|
|
|
|
ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
|
|
|
|
HasTemplateScope);
|
|
|
|
if (HasTemplateScope)
|
|
|
|
Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
|
|
|
|
|
2012-04-16 15:05:22 +08:00
|
|
|
// Set or update the scope flags.
|
2011-09-09 01:42:22 +08:00
|
|
|
bool AlreadyHasClassScope = Class.TopLevelClass;
|
2012-04-16 15:05:22 +08:00
|
|
|
unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope;
|
2011-09-09 01:42:22 +08:00
|
|
|
ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope);
|
|
|
|
ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope);
|
|
|
|
|
2012-04-06 23:10:17 +08:00
|
|
|
// Enter the scope of nested classes
|
|
|
|
if (!AlreadyHasClassScope)
|
|
|
|
Actions.ActOnStartDelayedMemberDeclarations(getCurScope(),
|
|
|
|
Class.TagOrTemplate);
|
2012-05-17 20:01:52 +08:00
|
|
|
if (!Class.LateParsedDeclarations.empty()) {
|
2012-04-16 15:05:22 +08:00
|
|
|
// Allow 'this' within late-parsed attributes.
|
|
|
|
Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate,
|
|
|
|
/*TypeQuals=*/0);
|
|
|
|
|
|
|
|
for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i){
|
|
|
|
Class.LateParsedDeclarations[i]->ParseLexedAttributes();
|
|
|
|
}
|
2011-09-09 01:42:22 +08:00
|
|
|
}
|
2012-04-16 15:05:22 +08:00
|
|
|
|
2012-04-06 23:10:17 +08:00
|
|
|
if (!AlreadyHasClassScope)
|
|
|
|
Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(),
|
|
|
|
Class.TagOrTemplate);
|
2011-09-09 01:42:22 +08:00
|
|
|
}
|
|
|
|
|
2012-02-17 00:50:43 +08:00
|
|
|
|
|
|
|
/// \brief Parse all attributes in LAs, and attach them to Decl D.
|
|
|
|
void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D,
|
|
|
|
bool EnterScope, bool OnDefinition) {
|
|
|
|
for (unsigned i = 0, ni = LAs.size(); i < ni; ++i) {
|
2012-03-03 06:12:59 +08:00
|
|
|
LAs[i]->addDecl(D);
|
2012-02-17 00:50:43 +08:00
|
|
|
ParseLexedAttribute(*LAs[i], EnterScope, OnDefinition);
|
2012-04-14 20:44:47 +08:00
|
|
|
delete LAs[i];
|
2012-02-17 00:50:43 +08:00
|
|
|
}
|
|
|
|
LAs.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-09 01:42:22 +08:00
|
|
|
/// \brief Finish parsing an attribute for which parsing was delayed.
|
|
|
|
/// This will be called at the end of parsing a class declaration
|
|
|
|
/// for each LateParsedAttribute. We consume the saved tokens and
|
|
|
|
/// create an attribute with the arguments filled in. We add this
|
|
|
|
/// to the Attribute list for the decl.
|
2012-02-17 00:50:43 +08:00
|
|
|
void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
|
|
|
|
bool EnterScope, bool OnDefinition) {
|
2011-09-09 01:42:22 +08:00
|
|
|
// Save the current token position.
|
|
|
|
SourceLocation OrigLoc = Tok.getLocation();
|
|
|
|
|
|
|
|
// Append the current token at the end of the new token stream so that it
|
|
|
|
// doesn't get lost.
|
|
|
|
LA.Toks.push_back(Tok);
|
|
|
|
PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false);
|
|
|
|
// Consume the previously pushed token.
|
|
|
|
ConsumeAnyToken();
|
|
|
|
|
2012-02-17 00:50:43 +08:00
|
|
|
if (OnDefinition && !IsThreadSafetyAttribute(LA.AttrName.getName())) {
|
|
|
|
Diag(Tok, diag::warn_attribute_on_function_definition)
|
|
|
|
<< LA.AttrName.getName();
|
|
|
|
}
|
|
|
|
|
2011-09-09 01:42:22 +08:00
|
|
|
ParsedAttributes Attrs(AttrFactory);
|
|
|
|
SourceLocation endLoc;
|
|
|
|
|
2012-03-03 06:12:59 +08:00
|
|
|
if (LA.Decls.size() == 1) {
|
|
|
|
Decl *D = LA.Decls[0];
|
2011-09-09 01:42:31 +08:00
|
|
|
|
2012-03-03 06:12:59 +08:00
|
|
|
// If the Decl is templatized, add template parameters to scope.
|
|
|
|
bool HasTemplateScope = EnterScope && D->isTemplateDecl();
|
|
|
|
ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope);
|
|
|
|
if (HasTemplateScope)
|
|
|
|
Actions.ActOnReenterTemplateScope(Actions.CurScope, D);
|
2011-09-09 01:42:22 +08:00
|
|
|
|
2012-03-03 06:12:59 +08:00
|
|
|
// If the Decl is on a function, add function parameters to the scope.
|
|
|
|
bool HasFunctionScope = EnterScope && D->isFunctionOrFunctionTemplate();
|
|
|
|
ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunctionScope);
|
|
|
|
if (HasFunctionScope)
|
|
|
|
Actions.ActOnReenterFunctionContext(Actions.CurScope, D);
|
|
|
|
|
|
|
|
ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc);
|
|
|
|
|
|
|
|
if (HasFunctionScope) {
|
|
|
|
Actions.ActOnExitFunctionContext();
|
|
|
|
FnScope.Exit(); // Pop scope, and remove Decls from IdResolver
|
|
|
|
}
|
|
|
|
if (HasTemplateScope) {
|
|
|
|
TempScope.Exit();
|
|
|
|
}
|
2012-03-03 06:29:50 +08:00
|
|
|
} else if (LA.Decls.size() > 0) {
|
2012-03-03 06:12:59 +08:00
|
|
|
// If there are multiple decls, then the decl cannot be within the
|
|
|
|
// function scope.
|
|
|
|
ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc);
|
2012-03-03 06:29:50 +08:00
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::warn_attribute_no_decl) << LA.AttrName.getName();
|
2011-09-09 01:42:31 +08:00
|
|
|
}
|
|
|
|
|
2012-03-03 06:12:59 +08:00
|
|
|
for (unsigned i = 0, ni = LA.Decls.size(); i < ni; ++i) {
|
|
|
|
Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.Decls[i], Attrs);
|
|
|
|
}
|
2011-09-09 01:42:22 +08:00
|
|
|
|
|
|
|
if (Tok.getLocation() != OrigLoc) {
|
|
|
|
// Due to a parsing error, we either went over the cached tokens or
|
|
|
|
// there are still cached tokens left, so we skip the leftover tokens.
|
|
|
|
// Since this is an uncommon situation that should be avoided, use the
|
|
|
|
// expensive isBeforeInTranslationUnit call.
|
|
|
|
if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
|
|
|
|
OrigLoc))
|
|
|
|
while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
|
2012-03-08 09:00:17 +08:00
|
|
|
ConsumeAnyToken();
|
2011-09-09 01:42:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-10 01:59:31 +08:00
|
|
|
/// \brief Wrapper around a case statement checking if AttrName is
|
|
|
|
/// one of the thread safety attributes
|
|
|
|
bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){
|
|
|
|
return llvm::StringSwitch<bool>(AttrName)
|
|
|
|
.Case("guarded_by", true)
|
|
|
|
.Case("guarded_var", true)
|
|
|
|
.Case("pt_guarded_by", true)
|
|
|
|
.Case("pt_guarded_var", true)
|
|
|
|
.Case("lockable", true)
|
|
|
|
.Case("scoped_lockable", true)
|
|
|
|
.Case("no_thread_safety_analysis", true)
|
|
|
|
.Case("acquired_after", true)
|
|
|
|
.Case("acquired_before", true)
|
|
|
|
.Case("exclusive_lock_function", true)
|
|
|
|
.Case("shared_lock_function", true)
|
|
|
|
.Case("exclusive_trylock_function", true)
|
|
|
|
.Case("shared_trylock_function", true)
|
|
|
|
.Case("unlock_function", true)
|
|
|
|
.Case("lock_returned", true)
|
|
|
|
.Case("locks_excluded", true)
|
|
|
|
.Case("exclusive_locks_required", true)
|
|
|
|
.Case("shared_locks_required", true)
|
|
|
|
.Default(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Parse the contents of thread safety attributes. These
|
|
|
|
/// should always be parsed as an expression list.
|
|
|
|
///
|
|
|
|
/// We need to special case the parsing due to the fact that if the first token
|
|
|
|
/// of the first argument is an identifier, the main parse loop will store
|
|
|
|
/// that token as a "parameter" and the rest of
|
|
|
|
/// the arguments will be added to a list of "arguments". However,
|
|
|
|
/// subsequent tokens in the first argument are lost. We instead parse each
|
|
|
|
/// argument as an expression and add all arguments to the list of "arguments".
|
|
|
|
/// In future, we will take advantage of this special case to also
|
|
|
|
/// deal with some argument scoping issues here (for example, referring to a
|
|
|
|
/// function parameter in the attribute on that function).
|
|
|
|
void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
|
|
|
|
SourceLocation AttrNameLoc,
|
|
|
|
ParsedAttributes &Attrs,
|
|
|
|
SourceLocation *EndLoc) {
|
2011-09-09 01:42:22 +08:00
|
|
|
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
2011-09-09 01:42:22 +08:00
|
|
|
|
|
|
|
ExprVector ArgExprs(Actions);
|
|
|
|
bool ArgExprsOk = true;
|
|
|
|
|
|
|
|
// now parse the list of expressions
|
2011-12-15 03:36:06 +08:00
|
|
|
while (Tok.isNot(tok::r_paren)) {
|
2011-09-09 01:42:22 +08:00
|
|
|
ExprResult ArgExpr(ParseAssignmentExpression());
|
|
|
|
if (ArgExpr.isInvalid()) {
|
|
|
|
ArgExprsOk = false;
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2011-09-09 01:42:22 +08:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
ArgExprs.push_back(ArgExpr.release());
|
2011-08-10 01:59:31 +08:00
|
|
|
}
|
2011-09-09 01:42:22 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
|
|
|
break;
|
|
|
|
ConsumeToken(); // Eat the comma, move to the next argument
|
|
|
|
}
|
|
|
|
// Match the ')'.
|
2012-01-21 06:50:54 +08:00
|
|
|
if (ArgExprsOk && !T.consumeClose()) {
|
2011-09-09 01:42:22 +08:00
|
|
|
Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(),
|
|
|
|
ArgExprs.take(), ArgExprs.size());
|
2011-08-10 01:59:31 +08:00
|
|
|
}
|
2011-10-13 00:37:45 +08:00
|
|
|
if (EndLoc)
|
|
|
|
*EndLoc = T.getCloseLocation();
|
2011-08-10 01:59:31 +08:00
|
|
|
}
|
|
|
|
|
2012-04-10 09:32:12 +08:00
|
|
|
/// DiagnoseProhibitedCXX11Attribute - We have found the opening square brackets
|
|
|
|
/// of a C++11 attribute-specifier in a location where an attribute is not
|
|
|
|
/// permitted. By C++11 [dcl.attr.grammar]p6, this is ill-formed. Diagnose this
|
|
|
|
/// situation.
|
|
|
|
///
|
|
|
|
/// \return \c true if we skipped an attribute-like chunk of tokens, \c false if
|
|
|
|
/// this doesn't appear to actually be an attribute-specifier, and the caller
|
|
|
|
/// should try to parse it.
|
|
|
|
bool Parser::DiagnoseProhibitedCXX11Attribute() {
|
|
|
|
assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square));
|
|
|
|
|
|
|
|
switch (isCXX11AttributeSpecifier(/*Disambiguate*/true)) {
|
|
|
|
case CAK_NotAttributeSpecifier:
|
|
|
|
// No diagnostic: we're in Obj-C++11 and this is not actually an attribute.
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case CAK_InvalidAttributeSpecifier:
|
|
|
|
Diag(Tok.getLocation(), diag::err_l_square_l_square_not_attribute);
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case CAK_AttributeSpecifier:
|
|
|
|
// Parse and discard the attributes.
|
|
|
|
SourceLocation BeginLoc = ConsumeBracket();
|
|
|
|
ConsumeBracket();
|
|
|
|
SkipUntil(tok::r_square, /*StopAtSemi*/ false);
|
|
|
|
assert(Tok.is(tok::r_square) && "isCXX11AttributeSpecifier lied");
|
|
|
|
SourceLocation EndLoc = ConsumeBracket();
|
|
|
|
Diag(BeginLoc, diag::err_attributes_not_allowed)
|
|
|
|
<< SourceRange(BeginLoc, EndLoc);
|
|
|
|
return true;
|
|
|
|
}
|
2012-04-11 00:03:08 +08:00
|
|
|
llvm_unreachable("All cases handled above.");
|
2012-04-10 09:32:12 +08:00
|
|
|
}
|
|
|
|
|
2010-12-24 10:08:15 +08:00
|
|
|
void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
|
|
|
|
Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed)
|
|
|
|
<< attrs.Range;
|
2010-09-03 09:29:35 +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
|
2012-04-14 08:33:13 +08:00
|
|
|
/// [C++11/C11] static_assert-declaration
|
2007-08-25 14:57:03 +08:00
|
|
|
/// others... [FIXME]
|
|
|
|
///
|
2010-09-29 04:42:35 +08:00
|
|
|
Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
|
|
|
|
unsigned Context,
|
2009-11-21 16:43:09 +08:00
|
|
|
SourceLocation &DeclEnd,
|
2010-12-24 10:08:15 +08:00
|
|
|
ParsedAttributesWithRange &attrs) {
|
2010-06-17 18:52:18 +08:00
|
|
|
ParenBraceBracketBalancer BalancerRAIIObj(*this);
|
2011-08-31 01:10:52 +08:00
|
|
|
// Must temporarily exit the objective-c container scope for
|
|
|
|
// parsing c none objective-c decls.
|
|
|
|
ObjCDeclContextSwitch ObjCDC(*this);
|
2010-06-17 18:52:18 +08:00
|
|
|
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *SingleDecl = 0;
|
2011-07-02 03:46:12 +08:00
|
|
|
Decl *OwnedType = 0;
|
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:
|
2010-12-24 10:08:15 +08:00
|
|
|
ProhibitAttributes(attrs);
|
2009-05-13 07:25:50 +08:00
|
|
|
SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd);
|
2009-03-30 00:50:03 +08:00
|
|
|
break;
|
2010-08-28 07:12:46 +08:00
|
|
|
case tok::kw_inline:
|
2010-08-31 08:36:45 +08:00
|
|
|
// Could be the start of an inline namespace. Allowed as an ext in C++03.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) {
|
2010-12-24 10:08:15 +08:00
|
|
|
ProhibitAttributes(attrs);
|
2010-08-28 07:12:46 +08:00
|
|
|
SourceLocation InlineLoc = ConsumeToken();
|
|
|
|
SingleDecl = ParseNamespace(Context, DeclEnd, InlineLoc);
|
|
|
|
break;
|
|
|
|
}
|
2010-12-24 10:08:15 +08:00
|
|
|
return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs,
|
2010-09-29 04:42:35 +08:00
|
|
|
true);
|
2007-08-25 14:57:03 +08:00
|
|
|
case tok::kw_namespace:
|
2010-12-24 10:08:15 +08:00
|
|
|
ProhibitAttributes(attrs);
|
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:
|
2010-11-10 10:40:36 +08:00
|
|
|
SingleDecl = ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(),
|
2011-07-02 03:46:12 +08:00
|
|
|
DeclEnd, attrs, &OwnedType);
|
2009-03-30 00:50:03 +08:00
|
|
|
break;
|
2009-03-12 00:27:10 +08:00
|
|
|
case tok::kw_static_assert:
|
2011-04-15 08:35:57 +08:00
|
|
|
case tok::kw__Static_assert:
|
2010-12-24 10:08:15 +08:00
|
|
|
ProhibitAttributes(attrs);
|
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:
|
2010-12-24 10:08:15 +08:00
|
|
|
return ParseSimpleDeclaration(Stmts, Context, DeclEnd, attrs, true);
|
2007-08-25 14:57:03 +08:00
|
|
|
}
|
2009-11-21 16:43:09 +08:00
|
|
|
|
2009-03-30 00:50:03 +08:00
|
|
|
// This routine returns a DeclGroup, if the thing we parsed only contains a
|
2011-07-02 03:46:12 +08:00
|
|
|
// single decl, convert it now. Alias declarations can also declare a type;
|
|
|
|
// include that too if it is present.
|
|
|
|
return Actions.ConvertDeclToDeclGroup(SingleDecl, OwnedType);
|
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
|
|
|
///
|
2011-04-15 06:09:26 +08:00
|
|
|
/// for-range-declaration: [C++0x 6.5p1: stmt.ranged]
|
|
|
|
/// attribute-specifier-seq[opt] type-specifier-seq declarator
|
|
|
|
///
|
2009-03-30 01:27:48 +08:00
|
|
|
/// If RequireSemi is false, this does not check for a ';' at the end of the
|
2010-04-06 02:18:31 +08:00
|
|
|
/// declaration. If it is true, it checks for and eats it.
|
2011-04-15 06:09:26 +08:00
|
|
|
///
|
|
|
|
/// If FRI is non-null, we might be parsing a for-range-declaration instead
|
|
|
|
/// of a simple-declaration. If we find that we are, we also parse the
|
|
|
|
/// for-range-initializer, and place it here.
|
2010-09-29 04:42:35 +08:00
|
|
|
Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts,
|
|
|
|
unsigned Context,
|
2009-11-21 16:43:09 +08:00
|
|
|
SourceLocation &DeclEnd,
|
2010-12-24 10:08:15 +08:00
|
|
|
ParsedAttributes &attrs,
|
2011-04-15 06:09:26 +08:00
|
|
|
bool RequireSemi,
|
|
|
|
ForRangeInit *FRI) {
|
2006-08-10 13:19:57 +08:00
|
|
|
// Parse the common declaration-specifiers piece.
|
2009-11-04 10:18:39 +08:00
|
|
|
ParsingDeclSpec DS(*this);
|
2010-12-24 10:08:15 +08:00
|
|
|
DS.takeAttributesFrom(attrs);
|
2011-04-24 13:37:28 +08:00
|
|
|
|
2010-01-14 01:31:36 +08:00
|
|
|
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
|
2011-02-20 11:19:35 +08:00
|
|
|
getDeclSpecContextFromDeclaratorContext(Context));
|
2012-01-07 18:52:36 +08:00
|
|
|
|
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)) {
|
2012-05-17 07:49:15 +08:00
|
|
|
DeclEnd = Tok.getLocation();
|
2010-04-06 02:18:31 +08:00
|
|
|
if (RequireSemi) ConsumeToken();
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
|
2011-04-24 13:37:28 +08:00
|
|
|
DS);
|
2009-11-04 10:18:39 +08:00
|
|
|
DS.complete(TheDecl);
|
2009-03-30 00:50:03 +08:00
|
|
|
return Actions.ConvertDeclToDeclGroup(TheDecl);
|
2006-08-14 03:58:17 +08:00
|
|
|
}
|
2011-04-24 13:37:28 +08:00
|
|
|
|
|
|
|
return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI);
|
2009-11-04 03:26:08 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-10-20 05:33:05 +08:00
|
|
|
/// Returns true if this might be the start of a declarator, or a common typo
|
|
|
|
/// for a declarator.
|
|
|
|
bool Parser::MightBeDeclarator(unsigned Context) {
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::annot_cxxscope:
|
|
|
|
case tok::annot_template_id:
|
|
|
|
case tok::caret:
|
|
|
|
case tok::code_completion:
|
|
|
|
case tok::coloncolon:
|
|
|
|
case tok::ellipsis:
|
|
|
|
case tok::kw___attribute:
|
|
|
|
case tok::kw_operator:
|
|
|
|
case tok::l_paren:
|
|
|
|
case tok::star:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case tok::amp:
|
|
|
|
case tok::ampamp:
|
2012-03-11 15:00:24 +08:00
|
|
|
return getLangOpts().CPlusPlus;
|
2011-10-20 05:33:05 +08:00
|
|
|
|
2012-01-10 06:31:44 +08:00
|
|
|
case tok::l_square: // Might be an attribute on an unnamed bit-field.
|
2012-03-11 15:00:24 +08:00
|
|
|
return Context == Declarator::MemberContext && getLangOpts().CPlusPlus0x &&
|
2012-01-10 06:31:44 +08:00
|
|
|
NextToken().is(tok::l_square);
|
|
|
|
|
|
|
|
case tok::colon: // Might be a typo for '::' or an unnamed bit-field.
|
2012-03-11 15:00:24 +08:00
|
|
|
return Context == Declarator::MemberContext || getLangOpts().CPlusPlus;
|
2012-01-10 06:31:44 +08:00
|
|
|
|
2011-10-20 05:33:05 +08:00
|
|
|
case tok::identifier:
|
|
|
|
switch (NextToken().getKind()) {
|
|
|
|
case tok::code_completion:
|
|
|
|
case tok::coloncolon:
|
|
|
|
case tok::comma:
|
|
|
|
case tok::equal:
|
|
|
|
case tok::equalequal: // Might be a typo for '='.
|
|
|
|
case tok::kw_alignas:
|
|
|
|
case tok::kw_asm:
|
|
|
|
case tok::kw___attribute:
|
|
|
|
case tok::l_brace:
|
|
|
|
case tok::l_paren:
|
|
|
|
case tok::l_square:
|
|
|
|
case tok::less:
|
|
|
|
case tok::r_brace:
|
|
|
|
case tok::r_paren:
|
|
|
|
case tok::r_square:
|
|
|
|
case tok::semi:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case tok::colon:
|
|
|
|
// At namespace scope, 'identifier:' is probably a typo for 'identifier::'
|
2012-01-10 06:31:44 +08:00
|
|
|
// and in block scope it's probably a label. Inside a class definition,
|
|
|
|
// this is a bit-field.
|
|
|
|
return Context == Declarator::MemberContext ||
|
2012-03-11 15:00:24 +08:00
|
|
|
(getLangOpts().CPlusPlus && Context == Declarator::FileContext);
|
2012-01-10 06:31:44 +08:00
|
|
|
|
|
|
|
case tok::identifier: // Possible virt-specifier.
|
2012-03-11 15:00:24 +08:00
|
|
|
return getLangOpts().CPlusPlus0x && isCXX0XVirtSpecifier(NextToken());
|
2011-10-20 05:33:05 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-12 04:59:20 +08:00
|
|
|
/// Skip until we reach something which seems like a sensible place to pick
|
|
|
|
/// up parsing after a malformed declaration. This will sometimes stop sooner
|
|
|
|
/// than SkipUntil(tok::r_brace) would, but will never stop later.
|
|
|
|
void Parser::SkipMalformedDecl() {
|
|
|
|
while (true) {
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::l_brace:
|
|
|
|
// Skip until matching }, then stop. We've probably skipped over
|
|
|
|
// a malformed class or function definition or similar.
|
|
|
|
ConsumeBrace();
|
|
|
|
SkipUntil(tok::r_brace, /*StopAtSemi*/false);
|
|
|
|
if (Tok.is(tok::comma) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try)) {
|
|
|
|
// This declaration isn't over yet. Keep skipping.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (Tok.is(tok::semi))
|
|
|
|
ConsumeToken();
|
|
|
|
return;
|
|
|
|
|
|
|
|
case tok::l_square:
|
|
|
|
ConsumeBracket();
|
|
|
|
SkipUntil(tok::r_square, /*StopAtSemi*/false);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case tok::l_paren:
|
|
|
|
ConsumeParen();
|
|
|
|
SkipUntil(tok::r_paren, /*StopAtSemi*/false);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case tok::r_brace:
|
|
|
|
return;
|
|
|
|
|
|
|
|
case tok::semi:
|
|
|
|
ConsumeToken();
|
|
|
|
return;
|
|
|
|
|
|
|
|
case tok::kw_inline:
|
|
|
|
// 'inline namespace' at the start of a line is almost certainly
|
|
|
|
// a good place to pick back up parsing.
|
|
|
|
if (Tok.isAtStartOfLine() && NextToken().is(tok::kw_namespace))
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::kw_namespace:
|
|
|
|
// 'namespace' at the start of a line is almost certainly a good
|
|
|
|
// place to pick back up parsing.
|
|
|
|
if (Tok.isAtStartOfLine())
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::eof:
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConsumeAnyToken();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-04 03:26:08 +08:00
|
|
|
/// ParseDeclGroup - Having concluded that this is either a function
|
|
|
|
/// definition or a group of object declarations, actually parse the
|
|
|
|
/// result.
|
2009-11-04 10:18:39 +08:00
|
|
|
Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
|
|
|
|
unsigned Context,
|
2009-11-04 03:26:08 +08:00
|
|
|
bool AllowFunctionDefinitions,
|
2011-04-15 06:09:26 +08:00
|
|
|
SourceLocation *DeclEnd,
|
|
|
|
ForRangeInit *FRI) {
|
2009-11-04 03:26:08 +08:00
|
|
|
// Parse the first declarator.
|
2009-11-04 10:18:39 +08:00
|
|
|
ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Context));
|
2009-11-04 03:26:08 +08:00
|
|
|
ParseDeclarator(D);
|
|
|
|
|
|
|
|
// Bail out if the first declarator didn't seem well-formed.
|
|
|
|
if (!D.hasName() && !D.mayOmitIdentifier()) {
|
2012-04-12 04:59:20 +08:00
|
|
|
SkipMalformedDecl();
|
2009-11-04 03:26:08 +08:00
|
|
|
return DeclGroupPtrTy();
|
|
|
|
}
|
2009-03-30 01:27:48 +08:00
|
|
|
|
2012-02-17 00:50:43 +08:00
|
|
|
// Save late-parsed attributes for now; they need to be parsed in the
|
|
|
|
// appropriate function scope after the function Decl has been constructed.
|
|
|
|
LateParsedAttrList LateParsedAttrs;
|
|
|
|
if (D.isFunctionDeclarator())
|
|
|
|
MaybeParseGNUAttributes(D, &LateParsedAttrs);
|
|
|
|
|
2010-07-12 06:24:20 +08:00
|
|
|
// Check to see if we have a function *definition* which must have a body.
|
|
|
|
if (AllowFunctionDefinitions && D.isFunctionDeclarator() &&
|
|
|
|
// Look at the next token to make sure that this isn't a function
|
|
|
|
// declaration. We have to check this because __attribute__ might be the
|
|
|
|
// start of a function definition in GCC-extended K&R C.
|
|
|
|
!isDeclarationAfterDeclarator()) {
|
2011-12-01 07:45:35 +08:00
|
|
|
|
2010-07-12 06:42:07 +08:00
|
|
|
if (isStartOfFunctionDefinition(D)) {
|
2009-11-04 03:26:08 +08:00
|
|
|
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
|
|
|
Diag(Tok, diag::err_function_declared_typedef);
|
|
|
|
|
|
|
|
// Recover by treating the 'typedef' as spurious.
|
|
|
|
DS.ClearStorageClassSpecs();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-02-17 00:50:43 +08:00
|
|
|
Decl *TheDecl =
|
|
|
|
ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs);
|
2009-11-04 03:26:08 +08:00
|
|
|
return Actions.ConvertDeclToDeclGroup(TheDecl);
|
2010-07-12 06:42:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isDeclarationSpecifier()) {
|
|
|
|
// If there is an invalid declaration specifier right after the function
|
|
|
|
// prototype, then we must be in a missing semicolon case where this isn't
|
|
|
|
// actually a body. Just fall through into the code that handles it as a
|
|
|
|
// prototype, and let the top-level code handle the erroneous declspec
|
|
|
|
// where it would otherwise expect a comma or semicolon.
|
2009-11-04 03:26:08 +08:00
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_expected_fn_body);
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return DeclGroupPtrTy();
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-02-17 00:50:43 +08:00
|
|
|
if (ParseAsmAttributesAfterDeclarator(D))
|
2011-04-15 06:09:26 +08:00
|
|
|
return DeclGroupPtrTy();
|
|
|
|
|
|
|
|
// C++0x [stmt.iter]p1: Check if we have a for-range-declarator. If so, we
|
|
|
|
// must parse and analyze the for-range-initializer before the declaration is
|
|
|
|
// analyzed.
|
|
|
|
if (FRI && Tok.is(tok::colon)) {
|
|
|
|
FRI->ColonLoc = ConsumeToken();
|
2011-06-05 20:23:16 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
|
|
|
FRI->RangeExpr = ParseBraceInitializer();
|
|
|
|
else
|
|
|
|
FRI->RangeExpr = ParseExpression();
|
2011-04-15 06:09:26 +08:00
|
|
|
Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
|
|
|
|
Actions.ActOnCXXForRangeDecl(ThisDecl);
|
|
|
|
Actions.FinalizeDeclaration(ThisDecl);
|
2012-01-27 09:29:43 +08:00
|
|
|
D.complete(ThisDecl);
|
2011-04-15 06:09:26 +08:00
|
|
|
return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1);
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 8> DeclsInGroup;
|
2011-04-15 06:09:26 +08:00
|
|
|
Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D);
|
2012-02-17 00:50:43 +08:00
|
|
|
if (LateParsedAttrs.size() > 0)
|
|
|
|
ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false);
|
2009-11-04 10:18:39 +08:00
|
|
|
D.complete(FirstDecl);
|
2010-08-21 17:40:31 +08:00
|
|
|
if (FirstDecl)
|
2009-11-04 03:26:08 +08:00
|
|
|
DeclsInGroup.push_back(FirstDecl);
|
|
|
|
|
2011-10-20 05:33:05 +08:00
|
|
|
bool ExpectSemi = Context != Declarator::ForContext;
|
|
|
|
|
2009-11-04 03:26:08 +08:00
|
|
|
// If we don't have a comma, it is either the end of the list (a ';') or an
|
|
|
|
// error, bail out.
|
|
|
|
while (Tok.is(tok::comma)) {
|
2011-10-20 05:33:05 +08:00
|
|
|
SourceLocation CommaLoc = ConsumeToken();
|
|
|
|
|
|
|
|
if (Tok.isAtStartOfLine() && ExpectSemi && !MightBeDeclarator(Context)) {
|
|
|
|
// This comma was followed by a line-break and something which can't be
|
|
|
|
// the start of a declarator. The comma was probably a typo for a
|
|
|
|
// semicolon.
|
|
|
|
Diag(CommaLoc, diag::err_expected_semi_declaration)
|
|
|
|
<< FixItHint::CreateReplacement(CommaLoc, ";");
|
|
|
|
ExpectSemi = false;
|
|
|
|
break;
|
|
|
|
}
|
2009-11-04 03:26:08 +08:00
|
|
|
|
|
|
|
// Parse the next declarator.
|
|
|
|
D.clear();
|
Improve 0-argument -Wvexing-parse diagnostic by adding notes with fix-its:
- If the declarator is at the start of a line, and the previous line contained
another declarator and ended with a comma, then that comma was probably a
typo for a semicolon:
int n = 0, m = 1, l = 2, // k = 5;
myImportantFunctionCall(); // oops!
- If removing the parentheses would correctly initialize the object, then
produce a note suggesting that fix.
- Otherwise, if there is a simple initializer we can suggest which performs
value-initialization, then provide a note suggesting a correction to that
initializer.
Sema::Declarator now tracks the location of the comma prior to the declarator in
the declaration, if there is one, to facilitate providing the note. The code to
determine an appropriate initializer from the -Wuninitialized warning has been
factored out to allow use in both that and -Wvexing-parse.
llvm-svn: 148072
2012-01-13 07:53:29 +08:00
|
|
|
D.setCommaLoc(CommaLoc);
|
2009-11-04 03:26:08 +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
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseGNUAttributes(D);
|
2009-11-04 03:26:08 +08:00
|
|
|
|
|
|
|
ParseDeclarator(D);
|
2012-01-13 08:14:12 +08:00
|
|
|
if (!D.isInvalidType()) {
|
|
|
|
Decl *ThisDecl = ParseDeclarationAfterDeclarator(D);
|
|
|
|
D.complete(ThisDecl);
|
|
|
|
if (ThisDecl)
|
|
|
|
DeclsInGroup.push_back(ThisDecl);
|
|
|
|
}
|
2009-03-30 01:18:04 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-04 03:26:08 +08:00
|
|
|
if (DeclEnd)
|
|
|
|
*DeclEnd = Tok.getLocation();
|
|
|
|
|
2011-10-20 05:33:05 +08:00
|
|
|
if (ExpectSemi &&
|
2012-04-29 00:12:17 +08:00
|
|
|
ExpectAndConsumeSemi(Context == Declarator::FileContext
|
|
|
|
? diag::err_invalid_token_after_toplevel_declarator
|
|
|
|
: diag::err_expected_semi_declaration)) {
|
2010-07-12 06:42:07 +08:00
|
|
|
// Okay, there was no semicolon and one was expected. If we see a
|
|
|
|
// declaration specifier, just assume it was missing and continue parsing.
|
|
|
|
// Otherwise things are very confused and we skip to recover.
|
|
|
|
if (!isDeclarationSpecifier()) {
|
|
|
|
SkipUntil(tok::r_brace, true, true);
|
|
|
|
if (Tok.is(tok::semi))
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
2009-11-04 03:26:08 +08:00
|
|
|
}
|
|
|
|
|
2010-07-03 01:43:08 +08:00
|
|
|
return Actions.FinalizeDeclaratorGroup(getCurScope(), DS,
|
2009-11-04 03:26:08 +08:00
|
|
|
DeclsInGroup.data(),
|
|
|
|
DeclsInGroup.size());
|
2006-08-10 13:19:57 +08:00
|
|
|
}
|
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
/// Parse an optional simple-asm-expr and attributes, and attach them to a
|
|
|
|
/// declarator. Returns true on an error.
|
2012-02-17 00:50:43 +08:00
|
|
|
bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) {
|
2011-04-15 06:09:26 +08:00
|
|
|
// If a simple-asm-expr is present, parse it.
|
|
|
|
if (Tok.is(tok::kw_asm)) {
|
|
|
|
SourceLocation Loc;
|
|
|
|
ExprResult AsmLabel(ParseSimpleAsm(&Loc));
|
|
|
|
if (AsmLabel.isInvalid()) {
|
|
|
|
SkipUntil(tok::semi, true, true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
D.setAsmLabel(AsmLabel.release());
|
|
|
|
D.SetRangeEnd(Loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
MaybeParseGNUAttributes(D);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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'
|
2011-06-05 20:23:16 +08:00
|
|
|
/// [C++0x] braced-init-list
|
2009-03-25 06:27:57 +08:00
|
|
|
///
|
|
|
|
/// 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
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D,
|
2009-06-24 07:11:28 +08:00
|
|
|
const ParsedTemplateInfo &TemplateInfo) {
|
2012-02-17 00:50:43 +08:00
|
|
|
if (ParseAsmAttributesAfterDeclarator(D))
|
2011-04-15 06:09:26 +08:00
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
|
|
|
|
const ParsedTemplateInfo &TemplateInfo) {
|
2009-05-13 05:31:51 +08:00
|
|
|
// Inform the current actions module that we just parsed this declarator.
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *ThisDecl = 0;
|
2009-09-26 02:43:00 +08:00
|
|
|
switch (TemplateInfo.Kind) {
|
|
|
|
case ParsedTemplateInfo::NonTemplate:
|
2010-07-03 01:43:08 +08:00
|
|
|
ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
|
2009-09-26 02:43:00 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ParsedTemplateInfo::Template:
|
|
|
|
case ParsedTemplateInfo::ExplicitSpecialization:
|
2010-07-03 01:43:08 +08:00
|
|
|
ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(),
|
2010-08-27 07:41:50 +08:00
|
|
|
MultiTemplateParamsArg(Actions,
|
2009-06-24 07:11:28 +08:00
|
|
|
TemplateInfo.TemplateParams->data(),
|
|
|
|
TemplateInfo.TemplateParams->size()),
|
2009-09-26 02:43:00 +08:00
|
|
|
D);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ParsedTemplateInfo::ExplicitInstantiation: {
|
2010-08-21 17:40:31 +08:00
|
|
|
DeclResult ThisRes
|
2010-07-03 01:43:08 +08:00
|
|
|
= Actions.ActOnExplicitInstantiation(getCurScope(),
|
2009-09-26 02:43:00 +08:00
|
|
|
TemplateInfo.ExternLoc,
|
|
|
|
TemplateInfo.TemplateLoc,
|
|
|
|
D);
|
|
|
|
if (ThisRes.isInvalid()) {
|
|
|
|
SkipUntil(tok::semi, true, true);
|
2010-08-21 17:40:31 +08:00
|
|
|
return 0;
|
2009-09-26 02:43:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ThisDecl = ThisRes.get();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-02-20 11:19:35 +08:00
|
|
|
bool TypeContainsAuto =
|
|
|
|
D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
|
|
|
|
|
2009-05-13 05:31:51 +08:00
|
|
|
// Parse declarator '=' initializer.
|
2012-01-19 06:54:52 +08:00
|
|
|
// If a '==' or '+=' is found, suggest a fixit to '='.
|
Extend the error of invalid token after declarations to include fixits for
!=, %=, ^=, &=, *=, -=, |=, /=, <<=, <=, >=, and >>= to =.
llvm-svn: 148499
2012-01-20 06:01:51 +08:00
|
|
|
if (isTokenEqualOrEqualTypo()) {
|
2009-05-13 05:31:51 +08:00
|
|
|
ConsumeToken();
|
2010-09-25 05:25:25 +08:00
|
|
|
if (Tok.is(tok::kw_delete)) {
|
2011-05-12 14:15:49 +08:00
|
|
|
if (D.isFunctionDeclarator())
|
|
|
|
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
|
|
|
|
<< 1 /* delete */;
|
|
|
|
else
|
|
|
|
Diag(ConsumeToken(), diag::err_deleted_non_function);
|
2011-05-06 09:42:00 +08:00
|
|
|
} else if (Tok.is(tok::kw_default)) {
|
2011-05-12 14:15:49 +08:00
|
|
|
if (D.isFunctionDeclarator())
|
2012-02-12 07:51:21 +08:00
|
|
|
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
|
|
|
|
<< 0 /* default */;
|
2011-05-12 14:15:49 +08:00
|
|
|
else
|
|
|
|
Diag(ConsumeToken(), diag::err_default_special_members);
|
2009-05-13 05:31:51 +08:00
|
|
|
} else {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
|
2009-12-19 17:28:58 +08:00
|
|
|
EnterScope(0);
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl);
|
2009-12-19 17:28:58 +08:00
|
|
|
}
|
2009-06-18 06:50:06 +08:00
|
|
|
|
2010-05-30 09:49:25 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteInitializer(getCurScope(), ThisDecl);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return 0;
|
2010-05-30 09:49:25 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Init(ParseInitializer());
|
2009-06-18 06:50:06 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
|
2009-12-19 17:28:58 +08:00
|
|
|
ExitScope();
|
|
|
|
}
|
2009-06-18 06:50:06 +08:00
|
|
|
|
2009-05-13 05:31:51 +08:00
|
|
|
if (Init.isInvalid()) {
|
2010-03-02 02:27:54 +08:00
|
|
|
SkipUntil(tok::comma, true, true);
|
|
|
|
Actions.ActOnInitializerError(ThisDecl);
|
|
|
|
} else
|
2011-02-20 11:19:35 +08:00
|
|
|
Actions.AddInitializerToDecl(ThisDecl, Init.take(),
|
|
|
|
/*DirectInit=*/false, TypeContainsAuto);
|
2009-05-13 05:31:51 +08:00
|
|
|
}
|
|
|
|
} else if (Tok.is(tok::l_paren)) {
|
|
|
|
// Parse C++ direct initializer: '(' expression-list ')'
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
|
|
|
|
2009-05-13 05:31:51 +08:00
|
|
|
ExprVector Exprs(Actions);
|
|
|
|
CommaLocsTy CommaLocs;
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
|
2009-12-23 01:47:17 +08:00
|
|
|
EnterScope(0);
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl);
|
2009-12-23 01:47:17 +08:00
|
|
|
}
|
|
|
|
|
2009-05-13 05:31:51 +08:00
|
|
|
if (ParseExpressionList(Exprs, CommaLocs)) {
|
|
|
|
SkipUntil(tok::r_paren);
|
2009-12-23 01:47:17 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
|
2009-12-23 01:47:17 +08:00
|
|
|
ExitScope();
|
|
|
|
}
|
2009-05-13 05:31:51 +08:00
|
|
|
} else {
|
|
|
|
// Match the ')'.
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2009-05-13 05:31:51 +08:00
|
|
|
|
|
|
|
assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
|
|
|
|
"Unexpected number of commas!");
|
2009-12-23 01:47:17 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
|
2009-12-23 01:47:17 +08:00
|
|
|
ExitScope();
|
|
|
|
}
|
|
|
|
|
Represent C++ direct initializers as ParenListExprs before semantic analysis
instead of having a special-purpose function.
- ActOnCXXDirectInitializer, which was mostly duplication of
AddInitializerToDecl (leading e.g. to PR10620, which Eli fixed a few days
ago), is dropped completely.
- MultiInitializer, which was an ugly hack I added, is dropped again.
- We now have the infrastructure in place to distinguish between
int x = {1};
int x({1});
int x{1};
-- VarDecl now has getInitStyle(), which indicates which of the above was used.
-- CXXConstructExpr now has a flag to indicate that it represents list-
initialization, although this is not yet used.
- InstantiateInitializer was renamed to SubstInitializer and simplified.
- ActOnParenOrParenListExpr has been replaced by ActOnParenListExpr, which
always produces a ParenListExpr. Placed that so far failed to convert that
back to a ParenExpr containing comma operators have been fixed. I'm pretty
sure I could have made a crashing test case before this.
The end result is a (I hope) considerably cleaner design of initializers.
More importantly, the fact that I can now distinguish between the various
initialization kinds means that I can get the tricky generalized initializer
test cases Johannes Schaub supplied to work. (This is not yet done.)
This commit passed self-host, with the resulting compiler passing the tests. I
hope it doesn't break more complicated code. It's a pretty big change, but one
that I feel is necessary.
llvm-svn: 150318
2012-02-12 07:51:47 +08:00
|
|
|
ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(),
|
|
|
|
T.getCloseLocation(),
|
|
|
|
move_arg(Exprs));
|
|
|
|
Actions.AddInitializerToDecl(ThisDecl, Initializer.take(),
|
|
|
|
/*DirectInit=*/true, TypeContainsAuto);
|
2009-05-13 05:31:51 +08:00
|
|
|
}
|
2012-03-11 15:00:24 +08:00
|
|
|
} else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
|
2011-06-05 20:23:16 +08:00
|
|
|
// Parse C++0x braced-init-list.
|
2011-10-15 13:09:34 +08:00
|
|
|
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
|
|
|
|
|
2011-06-05 20:23:16 +08:00
|
|
|
if (D.getCXXScopeSpec().isSet()) {
|
|
|
|
EnterScope(0);
|
|
|
|
Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl);
|
|
|
|
}
|
|
|
|
|
|
|
|
ExprResult Init(ParseBraceInitializer());
|
|
|
|
|
|
|
|
if (D.getCXXScopeSpec().isSet()) {
|
|
|
|
Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
|
|
|
|
ExitScope();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Init.isInvalid()) {
|
|
|
|
Actions.ActOnInitializerError(ThisDecl);
|
|
|
|
} else
|
|
|
|
Actions.AddInitializerToDecl(ThisDecl, Init.take(),
|
|
|
|
/*DirectInit=*/true, TypeContainsAuto);
|
|
|
|
|
2009-05-13 05:31:51 +08:00
|
|
|
} else {
|
2011-02-20 11:19:35 +08:00
|
|
|
Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto);
|
2009-05-13 05:31:51 +08:00
|
|
|
}
|
|
|
|
|
2011-02-22 04:05:19 +08:00
|
|
|
Actions.FinalizeDeclaration(ThisDecl);
|
|
|
|
|
2009-05-13 05:31:51 +08:00
|
|
|
return ThisDecl;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
///
|
2012-03-12 15:56:15 +08:00
|
|
|
void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
|
|
|
|
DeclSpecContext DSC) {
|
2006-08-13 09:16:23 +08:00
|
|
|
/// specifier-qualifier-list is a subset of declaration-specifiers. Just
|
|
|
|
/// parse declaration-specifiers and complain about extra stuff.
|
2011-09-30 02:04:28 +08:00
|
|
|
/// TODO: diagnose attribute-specifiers and alignment-specifiers.
|
2012-03-12 15:56:15 +08:00
|
|
|
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-08-13 09:16:23 +08:00
|
|
|
// Validate declspec for type-name.
|
|
|
|
unsigned Specs = DS.getParsedSpecifiers();
|
2012-05-10 04:55:26 +08:00
|
|
|
if ((DSC == DSC_type_specifier || DSC == DSC_trailing) &&
|
|
|
|
!DS.hasTypeSpecifier()) {
|
2012-03-12 15:56:15 +08:00
|
|
|
Diag(Tok, diag::err_expected_type);
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
} else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
|
|
|
|
!DS.hasAttributes()) {
|
2006-08-13 09:16:23 +08:00
|
|
|
Diag(Tok, diag::err_typename_requires_specqual);
|
2012-03-12 15:56:15 +08:00
|
|
|
if (!DS.hasTypeSpecifier())
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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
|
|
|
}
|
2009-09-09 23:08:12 +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
|
|
|
}
|
2012-03-12 15:56:15 +08:00
|
|
|
|
|
|
|
// Issue diagnostic and remove constexpr specfier if present.
|
|
|
|
if (DS.isConstexprSpecified()) {
|
|
|
|
Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr);
|
|
|
|
DS.ClearConstexprSpec();
|
|
|
|
}
|
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,
|
2012-03-12 15:56:15 +08:00
|
|
|
AccessSpecifier AS, DeclSpecContext DSC) {
|
2009-04-15 06:17:06 +08:00
|
|
|
assert(Tok.is(tok::identifier) && "should have identifier");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-15 05:34:55 +08:00
|
|
|
// Since we know that this either implicit int (which is rare) or an
|
2012-05-16 05:01:51 +08:00
|
|
|
// error, do lookahead to try to do better recovery. This never applies
|
|
|
|
// within a type specifier. Outside of C++, we allow this even if the
|
|
|
|
// language doesn't "officially" support implicit int -- we support
|
|
|
|
// implicit int as an extension in C99 and C11. Allegedly, MS also
|
|
|
|
// supports implicit int in C++ mode.
|
2012-05-10 04:55:26 +08:00
|
|
|
if (DSC != DSC_type_specifier && DSC != DSC_trailing &&
|
2012-05-16 05:01:51 +08:00
|
|
|
(!getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt) &&
|
2012-03-12 15:56:15 +08:00
|
|
|
isValidAfterIdentifierInDeclarator(NextToken())) {
|
2009-04-15 05:34:55 +08:00
|
|
|
// 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;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-05-16 05:01:51 +08:00
|
|
|
if (getLangOpts().CPlusPlus &&
|
|
|
|
DS.getStorageClassSpec() == DeclSpec::SCS_auto) {
|
|
|
|
// Don't require a type specifier if we have the 'auto' storage class
|
|
|
|
// specifier in C++98 -- we'll promote it to a type specifier.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-04-15 05:34:55 +08:00
|
|
|
// 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) {
|
2011-04-22 01:29:47 +08:00
|
|
|
const char *TagName = 0, *FixitTagName = 0;
|
2009-04-15 06:17:06 +08:00
|
|
|
tok::TokenKind TagKind = tok::unknown;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-03 01:43:08 +08:00
|
|
|
switch (Actions.isTagName(*Tok.getIdentifierInfo(), getCurScope())) {
|
2009-04-15 05:34:55 +08:00
|
|
|
default: break;
|
2011-04-22 01:29:47 +08:00
|
|
|
case DeclSpec::TST_enum:
|
|
|
|
TagName="enum" ; FixitTagName = "enum " ; TagKind=tok::kw_enum ;break;
|
|
|
|
case DeclSpec::TST_union:
|
|
|
|
TagName="union" ; FixitTagName = "union " ;TagKind=tok::kw_union ;break;
|
|
|
|
case DeclSpec::TST_struct:
|
|
|
|
TagName="struct"; FixitTagName = "struct ";TagKind=tok::kw_struct;break;
|
|
|
|
case DeclSpec::TST_class:
|
|
|
|
TagName="class" ; FixitTagName = "class " ;TagKind=tok::kw_class ;break;
|
2009-04-15 05:34:55 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-15 06:17:06 +08:00
|
|
|
if (TagName) {
|
2012-04-27 07:36:17 +08:00
|
|
|
IdentifierInfo *TokenName = Tok.getIdentifierInfo();
|
|
|
|
LookupResult R(Actions, TokenName, SourceLocation(),
|
|
|
|
Sema::LookupOrdinaryName);
|
|
|
|
|
2009-04-15 06:17:06 +08:00
|
|
|
Diag(Loc, diag::err_use_of_tag_name_without_tag)
|
2012-04-27 07:36:17 +08:00
|
|
|
<< TokenName << TagName << getLangOpts().CPlusPlus
|
|
|
|
<< FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName);
|
|
|
|
|
|
|
|
if (Actions.LookupParsedName(R, getCurScope(), SS)) {
|
|
|
|
for (LookupResult::iterator I = R.begin(), IEnd = R.end();
|
|
|
|
I != IEnd; ++I)
|
2012-04-28 02:26:49 +08:00
|
|
|
Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
|
2012-04-27 07:36:17 +08:00
|
|
|
<< TokenName << TagName;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-15 06:17:06 +08:00
|
|
|
// Parse this as a tag as if the missing tag were present.
|
|
|
|
if (TagKind == tok::kw_enum)
|
2012-03-12 15:56:15 +08:00
|
|
|
ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSC_normal);
|
2009-04-15 06:17:06 +08:00
|
|
|
else
|
2012-03-12 15:56:15 +08:00
|
|
|
ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS,
|
|
|
|
/*EnteringContext*/ false, DSC_normal);
|
2009-04-15 06:17:06 +08:00
|
|
|
return true;
|
|
|
|
}
|
2009-04-15 05:34:55 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-05-16 05:29:55 +08:00
|
|
|
// Determine whether this identifier could plausibly be the name of something
|
2012-05-16 05:42:17 +08:00
|
|
|
// being declared (with a missing type).
|
2012-05-16 05:29:55 +08:00
|
|
|
if (DSC != DSC_type_specifier && DSC != DSC_trailing &&
|
|
|
|
(!SS || DSC == DSC_top_level || DSC == DSC_class)) {
|
2012-05-16 05:01:51 +08:00
|
|
|
// Look ahead to the next token to try to figure out what this declaration
|
|
|
|
// was supposed to be.
|
|
|
|
switch (NextToken().getKind()) {
|
|
|
|
case tok::comma:
|
|
|
|
case tok::equal:
|
|
|
|
case tok::kw_asm:
|
|
|
|
case tok::l_brace:
|
|
|
|
case tok::l_square:
|
|
|
|
case tok::semi:
|
|
|
|
// This looks like a variable declaration. The type is probably missing.
|
|
|
|
// We're done parsing decl-specifiers.
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case tok::l_paren: {
|
|
|
|
// static x(4); // 'x' is not a type
|
|
|
|
// x(int n); // 'x' is not a type
|
|
|
|
// x (*p)[]; // 'x' is a type
|
|
|
|
//
|
|
|
|
// Since we're in an error case (or the rare 'implicit int in C++' MS
|
|
|
|
// extension), we can afford to perform a tentative parse to determine
|
|
|
|
// which case we're in.
|
|
|
|
TentativeParsingAction PA(*this);
|
|
|
|
ConsumeToken();
|
|
|
|
TPResult TPR = TryParseDeclarator(/*mayBeAbstract*/false);
|
|
|
|
PA.Revert();
|
|
|
|
if (TPR == TPResult::False())
|
|
|
|
return false;
|
|
|
|
// The identifier is followed by a parenthesized declarator.
|
|
|
|
// It's supposed to be a type.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
// This is probably supposed to be a type. This includes cases like:
|
|
|
|
// int f(itn);
|
|
|
|
// struct S { unsinged : 4; };
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-14 07:27:22 +08:00
|
|
|
// This is almost certainly an invalid type name. Let the action emit a
|
|
|
|
// diagnostic and attempt to recover.
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType T;
|
2009-10-14 07:27:22 +08:00
|
|
|
if (Actions.DiagnoseUnknownTypeName(*Tok.getIdentifierInfo(), Loc,
|
2010-07-03 01:43:08 +08:00
|
|
|
getCurScope(), SS, T)) {
|
2009-10-14 07:27:22 +08:00
|
|
|
// The action emitted a diagnostic, so we don't have to.
|
|
|
|
if (T) {
|
|
|
|
// The action has suggested that the type T could be used. Set that as
|
|
|
|
// the type in the declaration specifiers, consume the would-be type
|
|
|
|
// name token, and we're done.
|
|
|
|
const char *PrevSpec;
|
|
|
|
unsigned DiagID;
|
2010-08-24 13:47:05 +08:00
|
|
|
DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T);
|
2009-10-14 07:27:22 +08:00
|
|
|
DS.SetRangeEnd(Tok.getLocation());
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// There may be other declaration specifiers after this.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fall through; the action had no suggestion for us.
|
|
|
|
} else {
|
|
|
|
// The action did not emit a diagnostic, so emit one now.
|
|
|
|
SourceRange R;
|
|
|
|
if (SS) R = SS->getRange();
|
|
|
|
Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-10-14 07:27:22 +08:00
|
|
|
// Mark this as an error.
|
2012-03-12 15:56:15 +08:00
|
|
|
DS.SetTypeSpecError();
|
2009-04-15 05:34:55 +08:00
|
|
|
DS.SetRangeEnd(Tok.getLocation());
|
|
|
|
ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-15 05:34:55 +08:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2010-01-14 01:31:36 +08:00
|
|
|
/// \brief Determine the declaration specifier context from the declarator
|
|
|
|
/// context.
|
|
|
|
///
|
|
|
|
/// \param Context the declarator context, which is one of the
|
|
|
|
/// Declarator::TheContext enumerator values.
|
|
|
|
Parser::DeclSpecContext
|
|
|
|
Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
|
|
|
|
if (Context == Declarator::MemberContext)
|
|
|
|
return DSC_class;
|
|
|
|
if (Context == Declarator::FileContext)
|
|
|
|
return DSC_top_level;
|
2012-03-15 09:02:11 +08:00
|
|
|
if (Context == Declarator::TrailingReturnContext)
|
|
|
|
return DSC_trailing;
|
2010-01-14 01:31:36 +08:00
|
|
|
return DSC_normal;
|
|
|
|
}
|
|
|
|
|
2011-09-30 02:04:28 +08:00
|
|
|
/// ParseAlignArgument - Parse the argument to an alignment-specifier.
|
|
|
|
///
|
|
|
|
/// FIXME: Simply returns an alignof() expression if the argument is a
|
|
|
|
/// type. Ideally, the type should be propagated directly into Sema.
|
|
|
|
///
|
2011-12-24 01:00:35 +08:00
|
|
|
/// [C11] type-id
|
|
|
|
/// [C11] constant-expression
|
2011-10-24 04:07:52 +08:00
|
|
|
/// [C++0x] type-id ...[opt]
|
|
|
|
/// [C++0x] assignment-expression ...[opt]
|
|
|
|
ExprResult Parser::ParseAlignArgument(SourceLocation Start,
|
|
|
|
SourceLocation &EllipsisLoc) {
|
|
|
|
ExprResult ER;
|
2011-09-30 02:04:28 +08:00
|
|
|
if (isTypeIdInParens()) {
|
|
|
|
SourceLocation TypeLoc = Tok.getLocation();
|
|
|
|
ParsedType Ty = ParseTypeName().get();
|
|
|
|
SourceRange TypeRange(Start, Tok.getLocation());
|
2011-10-24 04:07:52 +08:00
|
|
|
ER = Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true,
|
|
|
|
Ty.getAsOpaquePtr(), TypeRange);
|
2011-09-30 02:04:28 +08:00
|
|
|
} else
|
2011-10-24 04:07:52 +08:00
|
|
|
ER = ParseConstantExpression();
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus0x && Tok.is(tok::ellipsis))
|
2011-10-25 01:56:00 +08:00
|
|
|
EllipsisLoc = ConsumeToken();
|
2011-10-24 04:07:52 +08:00
|
|
|
|
|
|
|
return ER;
|
2011-09-30 02:04:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseAlignmentSpecifier - Parse an alignment-specifier, and add the
|
|
|
|
/// attribute to Attrs.
|
|
|
|
///
|
|
|
|
/// alignment-specifier:
|
2011-12-24 01:00:35 +08:00
|
|
|
/// [C11] '_Alignas' '(' type-id ')'
|
|
|
|
/// [C11] '_Alignas' '(' constant-expression ')'
|
2011-10-24 04:07:52 +08:00
|
|
|
/// [C++0x] 'alignas' '(' type-id ...[opt] ')'
|
|
|
|
/// [C++0x] 'alignas' '(' assignment-expression ...[opt] ')'
|
2011-09-30 02:04:28 +08:00
|
|
|
void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
|
|
|
|
SourceLocation *endLoc) {
|
|
|
|
assert((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) &&
|
|
|
|
"Not an alignment-specifier!");
|
|
|
|
|
|
|
|
SourceLocation KWLoc = Tok.getLocation();
|
|
|
|
ConsumeToken();
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
if (T.expectAndConsume(diag::err_expected_lparen))
|
2011-09-30 02:04:28 +08:00
|
|
|
return;
|
|
|
|
|
2011-10-24 04:07:52 +08:00
|
|
|
SourceLocation EllipsisLoc;
|
|
|
|
ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation(), EllipsisLoc);
|
2011-09-30 02:04:28 +08:00
|
|
|
if (ArgExpr.isInvalid()) {
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2011-09-30 02:04:28 +08:00
|
|
|
if (endLoc)
|
2011-10-13 00:37:45 +08:00
|
|
|
*endLoc = T.getCloseLocation();
|
2011-09-30 02:04:28 +08:00
|
|
|
|
2011-10-24 04:07:52 +08:00
|
|
|
// FIXME: Handle pack-expansions here.
|
|
|
|
if (EllipsisLoc.isValid()) {
|
|
|
|
Diag(EllipsisLoc, diag::err_alignas_pack_exp_unsupported);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-09-30 02:04:28 +08:00
|
|
|
ExprVector ArgExprs(Actions);
|
|
|
|
ArgExprs.push_back(ArgExpr.release());
|
|
|
|
Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc,
|
2011-10-13 00:37:45 +08:00
|
|
|
0, T.getOpenLocation(), ArgExprs.take(), 1, false, true);
|
2011-09-30 02:04:28 +08:00
|
|
|
}
|
|
|
|
|
2006-07-31 13:13:43 +08:00
|
|
|
/// ParseDeclarationSpecifiers
|
|
|
|
/// declaration-specifiers: [C99 6.7]
|
2006-08-13 08:12:11 +08:00
|
|
|
/// storage-class-specifier declaration-specifiers[opt]
|
|
|
|
/// type-specifier declaration-specifiers[opt]
|
|
|
|
/// [C99] function-specifier declaration-specifiers[opt]
|
2011-12-24 01:00:35 +08:00
|
|
|
/// [C11] alignment-specifier declaration-specifiers[opt]
|
2006-08-15 12:50:22 +08:00
|
|
|
/// [GNU] attributes declaration-specifiers[opt]
|
2011-09-09 10:06:17 +08:00
|
|
|
/// [Clang] '__module_private__' 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'
|
2011-02-14 09:42:53 +08:00
|
|
|
/// [OpenCL] '__kernel'
|
2009-05-06 12:46:28 +08:00
|
|
|
/// 'friend': [C++ dcl.friend]
|
2009-11-05 23:47:02 +08:00
|
|
|
/// 'constexpr': [C++0x dcl.constexpr]
|
2009-05-06 12:46:28 +08:00
|
|
|
|
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,
|
2012-03-03 06:12:59 +08:00
|
|
|
DeclSpecContext DSContext,
|
|
|
|
LateParsedAttrList *LateAttrs) {
|
2011-04-24 13:37:28 +08:00
|
|
|
if (DS.getSourceRange().isInvalid()) {
|
|
|
|
DS.SetRangeStart(Tok.getLocation());
|
|
|
|
DS.SetRangeEnd(Tok.getLocation());
|
|
|
|
}
|
|
|
|
|
2011-11-08 01:33:42 +08:00
|
|
|
bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level);
|
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()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
default:
|
2008-07-26 08:20:22 +08:00
|
|
|
DoneWithDeclSpec:
|
2011-09-30 02:03:57 +08:00
|
|
|
// [C++0x] decl-specifier-seq: decl-specifier attribute-specifier-seq[opt]
|
|
|
|
MaybeParseCXX0XAttributes(DS.getAttributes());
|
|
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
2010-08-24 02:23:48 +08:00
|
|
|
case tok::code_completion: {
|
2010-08-27 07:41:50 +08:00
|
|
|
Sema::ParserCompletionContext CCC = Sema::PCC_Namespace;
|
2010-08-24 02:23:48 +08:00
|
|
|
if (DS.hasTypeSpecifier()) {
|
|
|
|
bool AllowNonIdentifiers
|
|
|
|
= (getCurScope()->getFlags() & (Scope::ControlScope |
|
|
|
|
Scope::BlockScope |
|
|
|
|
Scope::TemplateParamScope |
|
|
|
|
Scope::FunctionPrototypeScope |
|
|
|
|
Scope::AtCatchScope)) == 0;
|
|
|
|
bool AllowNestedNameSpecifiers
|
|
|
|
= DSContext == DSC_top_level ||
|
|
|
|
(DSContext == DSC_class && DS.isFriendSpecified());
|
|
|
|
|
Implement code completion for Objective-C class message sends that are
missing the opening bracket '[', e.g.,
NSArray <CC>
at function scope. Previously, we would only give trivial completions
(const, volatile, etc.), because we're in a "declaration name"
scope. Now, we also provide completions for class methods of NSArray,
e.g.,
alloc
Note that we already had support for this after the first argument,
e.g.,
NSArray method:x <CC>
would get code completion for class methods of NSArray whose selector
starts with "method:". This was already present because we recover
as if NSArray method:x were a class message send missing the opening
bracket (which was committed in r114057).
llvm-svn: 114078
2010-09-16 23:14:18 +08:00
|
|
|
Actions.CodeCompleteDeclSpec(getCurScope(), DS,
|
|
|
|
AllowNonIdentifiers,
|
|
|
|
AllowNestedNameSpecifiers);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2010-08-24 02:23:48 +08:00
|
|
|
}
|
|
|
|
|
2011-02-16 04:33:25 +08:00
|
|
|
if (getCurScope()->getFnParent() || getCurScope()->getBlockParent())
|
|
|
|
CCC = Sema::PCC_LocalDeclarationSpecifiers;
|
|
|
|
else if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate)
|
2010-08-27 07:41:50 +08:00
|
|
|
CCC = DSContext == DSC_class? Sema::PCC_MemberTemplate
|
|
|
|
: Sema::PCC_Template;
|
2010-08-24 02:23:48 +08:00
|
|
|
else if (DSContext == DSC_class)
|
2010-08-27 07:41:50 +08:00
|
|
|
CCC = Sema::PCC_Class;
|
2012-02-08 00:50:53 +08:00
|
|
|
else if (CurParsedObjCImpl)
|
2010-08-27 07:41:50 +08:00
|
|
|
CCC = Sema::PCC_ObjCImplementation;
|
2010-08-24 02:23:48 +08:00
|
|
|
|
|
|
|
Actions.CodeCompleteOrdinaryName(getCurScope(), CCC);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2010-08-24 02:23:48 +08:00
|
|
|
}
|
|
|
|
|
2009-01-05 08:07:25 +08:00
|
|
|
case tok::coloncolon: // ::foo::bar
|
2010-02-26 16:45:28 +08:00
|
|
|
// C++ scope specifier. Annotate and loop, or bail out on error.
|
|
|
|
if (TryAnnotateCXXScopeToken(true)) {
|
|
|
|
if (!DS.hasTypeSpecifier())
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
}
|
2010-03-02 02:20:46 +08:00
|
|
|
if (Tok.is(tok::coloncolon)) // ::new or ::delete
|
|
|
|
goto DoneWithDeclSpec;
|
2010-02-26 16:45:28 +08:00
|
|
|
continue;
|
2008-11-09 00:45:02 +08:00
|
|
|
|
|
|
|
case tok::annot_cxxscope: {
|
2012-05-10 02:56:43 +08:00
|
|
|
if (DS.hasTypeSpecifier() || DS.isTypeAltiVecVector())
|
2008-11-09 00:45:02 +08:00
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
2009-12-12 19:40:51 +08:00
|
|
|
CXXScopeSpec SS;
|
2011-02-25 01:54:50 +08:00
|
|
|
Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
|
|
|
|
Tok.getAnnotationRange(),
|
|
|
|
SS);
|
2009-12-12 19:40:51 +08:00
|
|
|
|
2008-11-09 00:45:02 +08:00
|
|
|
// We are looking for a qualified typename.
|
2009-03-25 23:40:00 +08:00
|
|
|
Token Next = NextToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
if (Next.is(tok::annot_template_id) &&
|
2009-03-25 23:40:00 +08:00
|
|
|
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>
|
2010-01-14 01:31:36 +08:00
|
|
|
|
|
|
|
// C++ [class.qual]p2:
|
|
|
|
// In a lookup in which the constructor is an acceptable lookup
|
|
|
|
// result and the nested-name-specifier nominates a class C:
|
|
|
|
//
|
|
|
|
// - if the name specified after the
|
|
|
|
// nested-name-specifier, when looked up in C, is the
|
|
|
|
// injected-class-name of C (Clause 9), or
|
|
|
|
//
|
|
|
|
// - if the name specified after the nested-name-specifier
|
|
|
|
// is the same as the identifier or the
|
|
|
|
// simple-template-id's template-name in the last
|
|
|
|
// component of the nested-name-specifier,
|
|
|
|
//
|
|
|
|
// the name is instead considered to name the constructor of
|
|
|
|
// class C.
|
|
|
|
//
|
|
|
|
// Thus, if the template-name is actually the constructor
|
|
|
|
// name, then the code is ill-formed; this interpretation is
|
|
|
|
// reinforced by the NAD status of core issue 635.
|
2011-06-22 14:09:49 +08:00
|
|
|
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next);
|
2010-04-13 14:39:49 +08:00
|
|
|
if ((DSContext == DSC_top_level ||
|
|
|
|
(DSContext == DSC_class && DS.isFriendSpecified())) &&
|
|
|
|
TemplateId->Name &&
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) {
|
2010-01-14 01:31:36 +08:00
|
|
|
if (isConstructorDeclarator()) {
|
|
|
|
// The user meant this to be an out-of-line constructor
|
|
|
|
// definition, but template arguments are not allowed
|
|
|
|
// there. Just allow this as a constructor; we'll
|
|
|
|
// complain about it later.
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The user meant this to name a type, but it actually names
|
|
|
|
// a constructor with some extraneous template
|
|
|
|
// arguments. Complain, then parse it as a type as the user
|
|
|
|
// intended.
|
|
|
|
Diag(TemplateId->TemplateNameLoc,
|
|
|
|
diag::err_out_of_line_template_id_names_constructor)
|
|
|
|
<< TemplateId->Name;
|
|
|
|
}
|
|
|
|
|
2009-12-12 19:40:51 +08:00
|
|
|
DS.getTypeSpecScope() = SS;
|
|
|
|
ConsumeToken(); // The C++ scope.
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(Tok.is(tok::annot_template_id) &&
|
2009-03-25 23:40:00 +08:00
|
|
|
"ParseOptionalCXXScopeSpecifier not working");
|
2011-03-02 08:47:37 +08:00
|
|
|
AnnotateTemplateIdTokenAsType();
|
2009-03-25 23:40:00 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-09-28 15:26:33 +08:00
|
|
|
if (Next.is(tok::annot_typename)) {
|
2009-12-12 19:40:51 +08:00
|
|
|
DS.getTypeSpecScope() = SS;
|
|
|
|
ConsumeToken(); // The C++ scope.
|
2010-08-24 13:47:05 +08:00
|
|
|
if (Tok.getAnnotationValue()) {
|
|
|
|
ParsedType T = getTypeAnnotation(Tok);
|
2010-11-22 18:30:56 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
|
|
|
|
Tok.getAnnotationEndLoc(),
|
2010-08-24 13:47:05 +08:00
|
|
|
PrevSpec, DiagID, T);
|
|
|
|
}
|
2009-09-28 15:26:33 +08:00
|
|
|
else
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
|
|
|
|
ConsumeToken(); // The typename
|
|
|
|
}
|
|
|
|
|
2009-03-25 23:40:00 +08:00
|
|
|
if (Next.isNot(tok::identifier))
|
2008-11-09 00:45:02 +08:00
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
2010-01-14 01:31:36 +08:00
|
|
|
// If we're in a context where the identifier could be a class name,
|
|
|
|
// check whether this is a constructor declaration.
|
2010-04-13 14:39:49 +08:00
|
|
|
if ((DSContext == DSC_top_level ||
|
|
|
|
(DSContext == DSC_class && DS.isFriendSpecified())) &&
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(),
|
2010-01-14 01:31:36 +08:00
|
|
|
&SS)) {
|
|
|
|
if (isConstructorDeclarator())
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
|
|
|
// As noted in C++ [class.qual]p2 (cited above), when the name
|
|
|
|
// of the class is qualified in a context where it could name
|
|
|
|
// a constructor, its a constructor name. However, we've
|
|
|
|
// looked at the declarator, and the user probably meant this
|
|
|
|
// to be a type. Complain that it isn't supposed to be treated
|
|
|
|
// as a type, then proceed to parse it as a type.
|
|
|
|
Diag(Next.getLocation(), diag::err_out_of_line_type_names_constructor)
|
|
|
|
<< Next.getIdentifierInfo();
|
|
|
|
}
|
2008-11-09 00:45:02 +08:00
|
|
|
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(),
|
|
|
|
Next.getLocation(),
|
2011-03-02 02:12:44 +08:00
|
|
|
getCurScope(), &SS,
|
|
|
|
false, false, ParsedType(),
|
2012-01-27 16:46:19 +08:00
|
|
|
/*IsCtorOrDtorName=*/false,
|
2011-03-02 02:12:44 +08:00
|
|
|
/*NonTrivialSourceInfo=*/true);
|
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
|
2009-09-09 23:08:12 +08:00
|
|
|
// typename.
|
2009-04-15 06:17:06 +08:00
|
|
|
if (TypeRep == 0) {
|
|
|
|
ConsumeToken(); // Eat the scope spec so the identifier is current.
|
2012-03-12 15:56:15 +08:00
|
|
|
if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext)) continue;
|
2008-11-09 00:45:02 +08:00
|
|
|
goto DoneWithDeclSpec;
|
2009-04-15 06:17:06 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-12 19:40:51 +08:00
|
|
|
DS.getTypeSpecScope() = SS;
|
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;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-09 00:45:02 +08:00
|
|
|
DS.SetRangeEnd(Tok.getLocation());
|
|
|
|
ConsumeToken(); // The typename.
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-22 03:48:37 +08:00
|
|
|
case tok::annot_typename: {
|
2010-08-24 13:47:05 +08:00
|
|
|
if (Tok.getAnnotationValue()) {
|
|
|
|
ParsedType T = getTypeAnnotation(Tok);
|
2010-11-22 20:50:03 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
|
2010-08-24 13:47:05 +08:00
|
|
|
DiagID, T);
|
|
|
|
} else
|
2009-04-02 05:51:26 +08:00
|
|
|
DS.SetTypeSpecError();
|
2010-04-06 02:18:31 +08:00
|
|
|
|
|
|
|
if (isInvalid)
|
|
|
|
break;
|
|
|
|
|
2009-01-22 03:48:37 +08:00
|
|
|
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
|
|
|
|
ConsumeToken(); // The typename
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-22 03:48:37 +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
|
2010-10-22 07:17:00 +08:00
|
|
|
// Objective-C interface.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (Tok.is(tok::less) && getLangOpts().ObjC1)
|
2010-10-22 07:17:00 +08:00
|
|
|
ParseObjCProtocolQualifiers(DS);
|
|
|
|
|
2009-01-22 03:48:37 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-04-28 23:48:45 +08:00
|
|
|
case tok::kw___is_signed:
|
|
|
|
// GNU libstdc++ 4.4 uses __is_signed as an identifier, but Clang
|
|
|
|
// typically treats it as a trait. If we see __is_signed as it appears
|
|
|
|
// in libstdc++, e.g.,
|
|
|
|
//
|
|
|
|
// static const bool __is_signed;
|
|
|
|
//
|
|
|
|
// then treat __is_signed as an identifier rather than as a keyword.
|
|
|
|
if (DS.getTypeSpecType() == TST_bool &&
|
|
|
|
DS.getTypeQualifiers() == DeclSpec::TQ_const &&
|
|
|
|
DS.getStorageClassSpec() == DeclSpec::SCS_static) {
|
|
|
|
Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
|
|
|
|
Tok.setKind(tok::identifier);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We're done with the declaration-specifiers.
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
2008-07-26 09:18:38 +08:00
|
|
|
// typedef-name
|
2011-12-04 13:04:18 +08:00
|
|
|
case tok::kw_decltype:
|
2008-07-26 09:18:38 +08:00
|
|
|
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.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus) {
|
2010-02-26 16:45:28 +08:00
|
|
|
if (TryAnnotateCXXScopeToken(true)) {
|
|
|
|
if (!DS.hasTypeSpecifier())
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
}
|
|
|
|
if (!Tok.is(tok::identifier))
|
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +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;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-05 08:12:22 +08:00
|
|
|
// Check for need to substitute AltiVec keyword tokens.
|
|
|
|
if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
|
|
|
|
break;
|
|
|
|
|
2012-05-10 02:56:43 +08:00
|
|
|
// [AltiVec] 2.2: [If the 'vector' specifier is used] The syntax does not
|
|
|
|
// allow the use of a typedef name as a type specifier.
|
|
|
|
if (DS.isTypeAltiVecVector())
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType TypeRep =
|
|
|
|
Actions.getTypeName(*Tok.getIdentifierInfo(),
|
|
|
|
Tok.getLocation(), getCurScope());
|
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.
|
2010-08-24 13:47:05 +08:00
|
|
|
if (!TypeRep) {
|
2012-03-12 15:56:15 +08:00
|
|
|
if (ParseImplicitInt(DS, 0, TemplateInfo, AS, DSContext)) 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
|
|
|
|
2010-01-14 01:31:36 +08:00
|
|
|
// If we're in a context where the identifier could be a class name,
|
|
|
|
// check whether this is a constructor declaration.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus && DSContext == DSC_class &&
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) &&
|
2010-01-14 01:31:36 +08:00
|
|
|
isConstructorDeclarator())
|
2008-10-31 17:07:45 +08:00
|
|
|
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;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-26 09:18:38 +08:00
|
|
|
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
|
2010-10-22 07:17:00 +08:00
|
|
|
// Objective-C interface.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (Tok.is(tok::less) && getLangOpts().ObjC1)
|
2010-10-22 07:17:00 +08:00
|
|
|
ParseObjCProtocolQualifiers(DS);
|
|
|
|
|
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: {
|
2011-06-22 14:09:49 +08:00
|
|
|
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
|
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;
|
|
|
|
}
|
|
|
|
|
2010-01-14 01:31:36 +08:00
|
|
|
// If we're in a context where the template-id could be a
|
|
|
|
// constructor name or specialization, check whether this is a
|
|
|
|
// constructor declaration.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus && DSContext == DSC_class &&
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) &&
|
2010-01-14 01:31:36 +08:00
|
|
|
isConstructorDeclarator())
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
|
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
|
|
|
// 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:
|
2012-03-03 06:12:59 +08:00
|
|
|
ParseGNUAttributes(DS.getAttributes(), 0, LateAttrs);
|
2006-10-17 11:01:08 +08:00
|
|
|
continue;
|
2008-12-25 04:59:21 +08:00
|
|
|
|
|
|
|
// Microsoft declspec support.
|
|
|
|
case tok::kw___declspec:
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseMicrosoftDeclSpec(DS.getAttributes());
|
2008-12-25 04:59:21 +08:00
|
|
|
continue;
|
2009-09-09 23:08:12 +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:
|
2011-08-25 08:36:46 +08:00
|
|
|
case tok::kw___ptr32:
|
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:
|
2010-05-19 00:57:00 +08:00
|
|
|
case tok::kw___thiscall:
|
2011-08-18 17:59:55 +08:00
|
|
|
case tok::kw___unaligned:
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseMicrosoftTypeAttributes(DS.getAttributes());
|
2009-06-09 07:27:34 +08:00
|
|
|
continue;
|
|
|
|
|
2010-09-03 09:29:35 +08:00
|
|
|
// Borland single token adornments.
|
|
|
|
case tok::kw___pascal:
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseBorlandTypeAttributes(DS.getAttributes());
|
2010-09-03 09:29:35 +08:00
|
|
|
continue;
|
|
|
|
|
2011-02-14 09:42:53 +08:00
|
|
|
// OpenCL single token adornments.
|
|
|
|
case tok::kw___kernel:
|
|
|
|
ParseOpenCLAttributes(DS.getAttributes());
|
|
|
|
continue;
|
|
|
|
|
2006-08-05 11:28:50 +08:00
|
|
|
// storage-class-specifier
|
|
|
|
case tok::kw_typedef:
|
2011-10-06 11:01:00 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(Actions, 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";
|
2011-10-06 11:01:00 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(Actions, 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__:
|
2011-10-06 11:01:00 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_private_extern,
|
|
|
|
Loc, 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";
|
2011-10-06 11:01:00 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc,
|
|
|
|
PrevSpec, DiagID);
|
2006-08-05 11:28:50 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_auto:
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus0x) {
|
2011-02-23 07:17:49 +08:00
|
|
|
if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
|
2011-10-06 11:01:00 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
|
|
|
|
PrevSpec, DiagID);
|
2011-02-23 07:17:49 +08:00
|
|
|
if (!isInvalid)
|
2011-09-05 03:54:14 +08:00
|
|
|
Diag(Tok, diag::ext_auto_storage_class)
|
2011-02-23 07:17:49 +08:00
|
|
|
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
|
2011-09-05 03:54:14 +08:00
|
|
|
} else
|
2011-02-23 07:17:49 +08:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
|
|
|
|
DiagID);
|
2011-09-05 03:54:14 +08:00
|
|
|
} else
|
2011-10-06 11:01:00 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
|
|
|
|
PrevSpec, DiagID);
|
2006-08-05 11:28:50 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_register:
|
2011-10-06 11:01:00 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(Actions, 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:
|
2011-10-06 11:01:00 +08:00
|
|
|
isInvalid = DS.SetStorageClassSpec(Actions, 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;
|
2009-09-09 23:08:12 +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
|
|
|
|
2011-09-30 02:04:28 +08:00
|
|
|
// alignment-specifier
|
|
|
|
case tok::kw__Alignas:
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().C11)
|
2011-12-24 01:00:35 +08:00
|
|
|
Diag(Tok, diag::ext_c11_alignas);
|
2011-09-30 02:04:28 +08:00
|
|
|
ParseAlignmentSpecifier(DS.getAttributes());
|
|
|
|
continue;
|
|
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
2011-09-09 10:06:17 +08:00
|
|
|
// Modules
|
|
|
|
case tok::kw___module_private__:
|
|
|
|
isInvalid = DS.setModulePrivateSpec(Loc, PrevSpec, DiagID);
|
|
|
|
break;
|
|
|
|
|
2009-11-05 23:47:02 +08:00
|
|
|
// constexpr
|
|
|
|
case tok::kw_constexpr:
|
|
|
|
isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID);
|
|
|
|
break;
|
|
|
|
|
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;
|
2011-04-28 09:59:37 +08:00
|
|
|
case tok::kw___int64:
|
|
|
|
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
|
|
|
|
DiagID);
|
|
|
|
break;
|
2009-01-22 03:48:37 +08:00
|
|
|
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;
|
2012-04-04 14:24:32 +08:00
|
|
|
case tok::kw___int128:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec,
|
|
|
|
DiagID);
|
|
|
|
break;
|
|
|
|
case tok::kw_half:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec,
|
|
|
|
DiagID);
|
|
|
|
break;
|
2009-01-22 03:48:37 +08:00
|
|
|
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:
|
2010-11-17 02:18:13 +08:00
|
|
|
if (Tok.is(tok::kw_bool) &&
|
|
|
|
DS.getTypeSpecType() != DeclSpec::TST_unspecified &&
|
|
|
|
DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
|
|
|
PrevSpec = ""; // Not used by the diagnostic.
|
|
|
|
DiagID = diag::err_bool_redeclaration;
|
2011-04-20 05:42:37 +08:00
|
|
|
// For better error recovery.
|
|
|
|
Tok.setKind(tok::identifier);
|
2010-11-17 02:18:13 +08:00
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
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;
|
2010-02-05 08:12:22 +08:00
|
|
|
case tok::kw___vector:
|
|
|
|
isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
|
|
|
|
break;
|
|
|
|
case tok::kw___pixel:
|
|
|
|
isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
|
|
|
|
break;
|
2011-04-10 06:50:59 +08:00
|
|
|
case tok::kw___unknown_anytype:
|
|
|
|
isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc,
|
|
|
|
PrevSpec, DiagID);
|
|
|
|
break;
|
2009-01-22 03:48:37 +08:00
|
|
|
|
|
|
|
// 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();
|
2012-03-12 15:56:15 +08:00
|
|
|
ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS,
|
|
|
|
EnteringContext, DSContext);
|
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();
|
2012-03-12 15:56:15 +08:00
|
|
|
ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSContext);
|
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,
|
2012-03-11 15:00:24 +08:00
|
|
|
getLangOpts());
|
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,
|
2012-03-11 15:00:24 +08:00
|
|
|
getLangOpts());
|
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,
|
2012-03-11 15:00:24 +08:00
|
|
|
getLangOpts());
|
2009-01-22 03:48:37 +08:00
|
|
|
break;
|
|
|
|
|
2009-03-28 07:10:48 +08:00
|
|
|
// C++ typename-specifier:
|
|
|
|
case tok::kw_typename:
|
2010-02-26 16:45:28 +08:00
|
|
|
if (TryAnnotateTypeOrScopeToken()) {
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
}
|
|
|
|
if (!Tok.is(tok::kw_typename))
|
2009-03-28 07:10:48 +08:00
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
|
2009-01-22 03:48:37 +08:00
|
|
|
// GNU typeof support.
|
|
|
|
case tok::kw_typeof:
|
|
|
|
ParseTypeofSpecifier(DS);
|
|
|
|
continue;
|
|
|
|
|
2011-12-04 13:04:18 +08:00
|
|
|
case tok::annot_decltype:
|
2009-06-25 01:47:40 +08:00
|
|
|
ParseDecltypeSpecifier(DS);
|
|
|
|
continue;
|
|
|
|
|
2011-05-19 13:37:45 +08:00
|
|
|
case tok::kw___underlying_type:
|
|
|
|
ParseUnderlyingTypeSpecifier(DS);
|
2011-10-07 07:00:33 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
case tok::kw__Atomic:
|
|
|
|
ParseAtomicSpecifier(DS);
|
|
|
|
continue;
|
2011-05-19 13:37:45 +08:00
|
|
|
|
2011-03-19 06:38:29 +08:00
|
|
|
// OpenCL qualifiers:
|
|
|
|
case tok::kw_private:
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().OpenCL)
|
2011-03-19 06:38:29 +08:00
|
|
|
goto DoneWithDeclSpec;
|
|
|
|
case tok::kw___private:
|
|
|
|
case tok::kw___global:
|
|
|
|
case tok::kw___local:
|
|
|
|
case tok::kw___constant:
|
|
|
|
case tok::kw___read_only:
|
|
|
|
case tok::kw___write_only:
|
|
|
|
case tok::kw___read_write:
|
|
|
|
ParseOpenCLQualifiers(DS);
|
|
|
|
break;
|
|
|
|
|
2008-06-05 08:02:44 +08:00
|
|
|
case tok::less:
|
2008-07-26 09:18:38 +08:00
|
|
|
// GCC ObjC supports types like "<SomeProtocol>" as a synonym for
|
2008-07-26 08:20:22 +08:00
|
|
|
// "id<SomeProtocol>". This is hopelessly old fashioned and dangerous,
|
|
|
|
// but we support it.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (DS.hasTypeSpecifier() || !getLangOpts().ObjC1)
|
2008-07-26 08:20:22 +08:00
|
|
|
goto DoneWithDeclSpec;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-11-20 01:10:50 +08:00
|
|
|
if (!ParseObjCProtocolQualifiers(DS))
|
|
|
|
Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id)
|
|
|
|
<< FixItHint::CreateInsertion(Loc, "id")
|
|
|
|
<< SourceRange(Loc, DS.getSourceRange().getEnd());
|
2010-10-22 07:17:00 +08:00
|
|
|
|
|
|
|
// Need to support trailing type qualifiers (e.g. "id<p> const").
|
|
|
|
// If a type specifier follows, it will be diagnosed elsewhere.
|
|
|
|
continue;
|
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);
|
2010-08-23 22:34:43 +08:00
|
|
|
|
|
|
|
if (DiagID == diag::ext_duplicate_declspec)
|
|
|
|
Diag(Tok, DiagID)
|
|
|
|
<< PrevSpec << FixItHint::CreateRemoval(Tok.getLocation());
|
|
|
|
else
|
|
|
|
Diag(Tok, DiagID) << PrevSpec;
|
2006-08-04 12:39:53 +08:00
|
|
|
}
|
2011-02-23 07:17:49 +08:00
|
|
|
|
2008-03-13 14:29:04 +08:00
|
|
|
DS.SetRangeEnd(Tok.getLocation());
|
2011-04-20 05:42:37 +08:00
|
|
|
if (DiagID != diag::err_bool_redeclaration)
|
|
|
|
ConsumeToken();
|
2006-07-31 13:13:43 +08:00
|
|
|
}
|
|
|
|
}
|
2008-12-02 07:54:00 +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::
|
2009-11-03 10:38:08 +08:00
|
|
|
ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) {
|
2011-08-22 23:54:49 +08:00
|
|
|
|
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);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-21 06:28:22 +08:00
|
|
|
// Parse the common specifier-qualifiers-list piece.
|
|
|
|
ParseSpecifierQualifierList(DS);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, DS);
|
2007-08-21 06:28:22 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read struct-declarators until we find the semicolon.
|
2009-11-03 10:38:08 +08:00
|
|
|
bool FirstDeclarator = true;
|
Improve 0-argument -Wvexing-parse diagnostic by adding notes with fix-its:
- If the declarator is at the start of a line, and the previous line contained
another declarator and ended with a comma, then that comma was probably a
typo for a semicolon:
int n = 0, m = 1, l = 2, // k = 5;
myImportantFunctionCall(); // oops!
- If removing the parentheses would correctly initialize the object, then
produce a note suggesting that fix.
- Otherwise, if there is a simple initializer we can suggest which performs
value-initialization, then provide a note suggesting a correction to that
initializer.
Sema::Declarator now tracks the location of the comma prior to the declarator in
the declaration, if there is one, to facilitate providing the note. The code to
determine an appropriate initializer from the -Wuninitialized warning has been
factored out to allow use in both that and -Wvexing-parse.
llvm-svn: 148072
2012-01-13 07:53:29 +08:00
|
|
|
SourceLocation CommaLoc;
|
2007-08-21 06:28:22 +08:00
|
|
|
while (1) {
|
2012-05-07 14:16:41 +08:00
|
|
|
ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
|
2009-11-03 10:38:08 +08:00
|
|
|
FieldDeclarator DeclaratorInfo(DS);
|
Improve 0-argument -Wvexing-parse diagnostic by adding notes with fix-its:
- If the declarator is at the start of a line, and the previous line contained
another declarator and ended with a comma, then that comma was probably a
typo for a semicolon:
int n = 0, m = 1, l = 2, // k = 5;
myImportantFunctionCall(); // oops!
- If removing the parentheses would correctly initialize the object, then
produce a note suggesting that fix.
- Otherwise, if there is a simple initializer we can suggest which performs
value-initialization, then provide a note suggesting a correction to that
initializer.
Sema::Declarator now tracks the location of the comma prior to the declarator in
the declaration, if there is one, to facilitate providing the note. The code to
determine an appropriate initializer from the -Wuninitialized warning has been
factored out to allow use in both that and -Wvexing-parse.
llvm-svn: 148072
2012-01-13 07:53:29 +08:00
|
|
|
DeclaratorInfo.D.setCommaLoc(CommaLoc);
|
2009-11-03 10:38:08 +08:00
|
|
|
|
|
|
|
// Attributes are only allowed here on successive declarators.
|
2010-12-24 10:08:15 +08:00
|
|
|
if (!FirstDeclarator)
|
|
|
|
MaybeParseGNUAttributes(DeclaratorInfo.D);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-21 06:28:22 +08:00
|
|
|
/// struct-declarator: declarator
|
|
|
|
/// struct-declarator: declarator[opt] ':' constant-expression
|
2009-12-10 09:59:24 +08:00
|
|
|
if (Tok.isNot(tok::colon)) {
|
|
|
|
// Don't parse FOO:BAR as if it were a typo for FOO::BAR.
|
|
|
|
ColonProtectionRAIIObject X(*this);
|
2008-04-10 14:46:29 +08:00
|
|
|
ParseDeclarator(DeclaratorInfo.D);
|
2009-12-10 09:59:24 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::colon)) {
|
2007-08-21 06:28:22 +08:00
|
|
|
ConsumeToken();
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult 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.
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseGNUAttributes(DeclaratorInfo.D);
|
2009-02-10 02:23:29 +08:00
|
|
|
|
2009-11-03 10:38:08 +08:00
|
|
|
// We're done with this declarator; invoke the callback.
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *D = Fields.invoke(DeclaratorInfo);
|
2009-11-04 10:18:39 +08:00
|
|
|
PD.complete(D);
|
2009-11-03 10:38:08 +08:00
|
|
|
|
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.
|
Improve 0-argument -Wvexing-parse diagnostic by adding notes with fix-its:
- If the declarator is at the start of a line, and the previous line contained
another declarator and ended with a comma, then that comma was probably a
typo for a semicolon:
int n = 0, m = 1, l = 2, // k = 5;
myImportantFunctionCall(); // oops!
- If removing the parentheses would correctly initialize the object, then
produce a note suggesting that fix.
- Otherwise, if there is a simple initializer we can suggest which performs
value-initialization, then provide a note suggesting a correction to that
initializer.
Sema::Declarator now tracks the location of the comma prior to the declarator in
the declaration, if there is one, to facilitate providing the note. The code to
determine an appropriate initializer from the -Wuninitialized warning has been
factored out to allow use in both that and -Wvexing-parse.
llvm-svn: 148072
2012-01-13 07:53:29 +08:00
|
|
|
CommaLoc = ConsumeToken();
|
2009-02-10 02:23:29 +08:00
|
|
|
|
2009-11-03 10:38:08 +08:00
|
|
|
FirstDeclarator = false;
|
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,
|
2010-08-21 17:40:31 +08:00
|
|
|
unsigned TagType, Decl *TagDecl) {
|
2010-08-27 07:41:50 +08:00
|
|
|
PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc,
|
|
|
|
"parsing struct/union body");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_brace);
|
|
|
|
if (T.consumeOpen())
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-10 06:42:13 +08:00
|
|
|
ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
|
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
|
|
|
|
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++.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) {
|
2011-12-30 05:57:33 +08:00
|
|
|
Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union);
|
|
|
|
Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union);
|
|
|
|
}
|
2007-01-24 04:11:08 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 32> FieldDecls;
|
2008-04-10 14:46:29 +08:00
|
|
|
|
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.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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)) {
|
2012-05-17 03:04:59 +08:00
|
|
|
ConsumeExtraSemi(InsideStruct,
|
|
|
|
DeclSpec::getSpecifierName((DeclSpec::TST)TagType));
|
2007-06-09 13:49:55 +08:00
|
|
|
continue;
|
|
|
|
}
|
2008-04-10 14:46:29 +08:00
|
|
|
|
|
|
|
// Parse all the comma separated declarators.
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2009-11-03 10:38:08 +08:00
|
|
|
|
2008-06-22 03:39:06 +08:00
|
|
|
if (!Tok.is(tok::at)) {
|
2009-11-03 10:38:08 +08:00
|
|
|
struct CFieldCallback : FieldCallback {
|
|
|
|
Parser &P;
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *TagDecl;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<Decl *> &FieldDecls;
|
2009-11-03 10:38:08 +08:00
|
|
|
|
2010-08-21 17:40:31 +08:00
|
|
|
CFieldCallback(Parser &P, Decl *TagDecl,
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<Decl *> &FieldDecls) :
|
2009-11-03 10:38:08 +08:00
|
|
|
P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {}
|
|
|
|
|
2010-08-21 17:40:31 +08:00
|
|
|
virtual Decl *invoke(FieldDeclarator &FD) {
|
2009-11-03 10:38:08 +08:00
|
|
|
// Install the declarator into the current TagDecl.
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Field = P.Actions.ActOnField(P.getCurScope(), TagDecl,
|
2009-11-04 05:13:47 +08:00
|
|
|
FD.D.getDeclSpec().getSourceRange().getBegin(),
|
|
|
|
FD.D, FD.BitfieldSize);
|
2009-11-03 10:38:08 +08:00
|
|
|
FieldDecls.push_back(Field);
|
|
|
|
return Field;
|
2009-08-26 22:27:30 +08:00
|
|
|
}
|
2009-11-03 10:38:08 +08:00
|
|
|
} Callback(*this, TagDecl, FieldDecls);
|
|
|
|
|
|
|
|
ParseStructDeclaration(DS, Callback);
|
2008-06-22 03:39:06 +08:00
|
|
|
} else { // Handle @defs
|
|
|
|
ConsumeToken();
|
|
|
|
if (!Tok.isObjCAtKeyword(tok::objc_defs)) {
|
|
|
|
Diag(Tok, diag::err_unexpected_at);
|
2010-02-02 08:37:27 +08:00
|
|
|
SkipUntil(tok::semi, true);
|
2008-06-22 03:39:06 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ConsumeToken();
|
|
|
|
ExpectAndConsume(tok::l_paren, diag::err_expected_lparen);
|
|
|
|
if (!Tok.is(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
2010-02-02 08:37:27 +08:00
|
|
|
SkipUntil(tok::semi, true);
|
2008-06-22 03:39:06 +08:00
|
|
|
continue;
|
|
|
|
}
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 16> Fields;
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnDefs(getCurScope(), TagDecl, Tok.getLocation(),
|
2008-12-12 00:49:14 +08:00
|
|
|
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);
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
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)) {
|
2010-02-02 08:37:27 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::ext_expected_semi_decl_list);
|
2007-06-09 13:54:40 +08:00
|
|
|
break;
|
2007-01-23 12:38:16 +08:00
|
|
|
} else {
|
2010-02-02 08:37:27 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
|
|
|
|
// Skip to end of block or statement to avoid ext-warning on extra ';'.
|
2007-01-23 12:38:16 +08:00
|
|
|
SkipUntil(tok::r_brace, true, true);
|
2010-02-02 08:37:27 +08:00
|
|
|
// If we stopped at a ';', eat it.
|
|
|
|
if (Tok.is(tok::semi)) ConsumeToken();
|
2007-01-23 12:38:16 +08:00
|
|
|
}
|
2006-08-14 06:21:02 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
2007-01-23 12:38:16 +08:00
|
|
|
// If attributes exist after struct contents, parse them.
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseGNUAttributes(attrs);
|
2008-10-03 10:03:53 +08:00
|
|
|
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnFields(getCurScope(),
|
2011-09-22 10:58:26 +08:00
|
|
|
RecordLoc, TagDecl, FieldDecls,
|
2011-10-13 00:37:45 +08:00
|
|
|
T.getOpenLocation(), T.getCloseLocation(),
|
2010-12-24 10:08:15 +08:00
|
|
|
attrs.getList());
|
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
|
|
|
StructScope.Exit();
|
2011-10-13 00:37:45 +08:00
|
|
|
Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl,
|
|
|
|
T.getCloseLocation());
|
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]
|
2012-03-01 12:09:28 +08:00
|
|
|
/// [MS] 'enum' __declspec[opt] identifier[opt] '{' enumerator-list ',' [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
|
|
|
///
|
2012-03-23 11:33:32 +08:00
|
|
|
/// [C++11] enum-head '{' enumerator-list[opt] '}'
|
|
|
|
/// [C++11] enum-head '{' enumerator-list ',' '}'
|
2010-10-09 07:50:27 +08:00
|
|
|
///
|
2012-03-23 11:33:32 +08:00
|
|
|
/// enum-head: [C++11]
|
|
|
|
/// enum-key attribute-specifier-seq[opt] identifier[opt] enum-base[opt]
|
|
|
|
/// enum-key attribute-specifier-seq[opt] nested-name-specifier
|
|
|
|
/// identifier enum-base[opt]
|
2010-10-09 07:50:27 +08:00
|
|
|
///
|
2012-03-23 11:33:32 +08:00
|
|
|
/// enum-key: [C++11]
|
2010-10-09 07:50:27 +08:00
|
|
|
/// 'enum'
|
|
|
|
/// 'enum' 'class'
|
|
|
|
/// 'enum' 'struct'
|
|
|
|
///
|
2012-03-23 11:33:32 +08:00
|
|
|
/// enum-base: [C++11]
|
2010-10-09 07:50:27 +08:00
|
|
|
/// ':' type-specifier-seq
|
|
|
|
///
|
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,
|
2010-03-03 01:53:14 +08:00
|
|
|
const ParsedTemplateInfo &TemplateInfo,
|
2012-03-12 15:56:15 +08:00
|
|
|
AccessSpecifier AS, DeclSpecContext DSC) {
|
2007-01-25 15:29:02 +08:00
|
|
|
// Parse the tag portion of this.
|
2009-09-18 23:37:17 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
// Code completion for an enum name.
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteTag(getCurScope(), DeclSpec::TST_enum);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2009-09-18 23:37:17 +08:00
|
|
|
}
|
2011-07-06 13:58:41 +08:00
|
|
|
|
2012-01-10 09:33:14 +08:00
|
|
|
SourceLocation ScopedEnumKWLoc;
|
2011-07-06 13:58:41 +08:00
|
|
|
bool IsScopedUsingClassTag = false;
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus0x &&
|
2011-07-06 13:58:41 +08:00
|
|
|
(Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) {
|
2011-10-15 13:09:34 +08:00
|
|
|
Diag(Tok, diag::warn_cxx98_compat_scoped_enum);
|
2011-07-06 13:58:41 +08:00
|
|
|
IsScopedUsingClassTag = Tok.is(tok::kw_class);
|
2012-01-10 09:33:14 +08:00
|
|
|
ScopedEnumKWLoc = ConsumeToken();
|
2011-07-06 13:58:41 +08:00
|
|
|
}
|
2012-03-23 11:33:32 +08:00
|
|
|
|
2012-05-07 14:16:58 +08:00
|
|
|
// C++11 [temp.explicit]p12:
|
|
|
|
// The usual access controls do not apply to names used to specify
|
|
|
|
// explicit instantiations.
|
|
|
|
// We extend this to also cover explicit specializations. Note that
|
|
|
|
// we don't suppress if this turns out to be an elaborated type
|
|
|
|
// specifier.
|
|
|
|
bool shouldDelayDiagsInTag =
|
|
|
|
(TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
|
|
|
|
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
|
|
|
|
SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag);
|
2012-03-23 11:33:32 +08:00
|
|
|
|
2008-09-11 08:21:41 +08:00
|
|
|
// If attributes exist after tag, parse them.
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseGNUAttributes(attrs);
|
2008-11-09 00:45:02 +08:00
|
|
|
|
2012-03-01 12:09:28 +08:00
|
|
|
// If declspecs exist after tag, parse them.
|
|
|
|
while (Tok.is(tok::kw___declspec))
|
|
|
|
ParseMicrosoftDeclSpec(attrs);
|
|
|
|
|
2012-03-12 16:56:40 +08:00
|
|
|
// Enum definitions should not be parsed in a trailing-return-type.
|
|
|
|
bool AllowDeclaration = DSC != DSC_trailing;
|
|
|
|
|
|
|
|
bool AllowFixedUnderlyingType = AllowDeclaration &&
|
|
|
|
(getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt ||
|
|
|
|
getLangOpts().ObjC2);
|
2011-07-06 13:58:41 +08:00
|
|
|
|
2010-05-20 05:37:53 +08:00
|
|
|
CXXScopeSpec &SS = DS.getTypeSpecScope();
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus) {
|
2011-07-06 13:58:41 +08:00
|
|
|
// "enum foo : bar;" is not a potential typo for "enum foo::bar;"
|
|
|
|
// if a fixed underlying type is allowed.
|
|
|
|
ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType);
|
|
|
|
|
2011-11-08 01:33:42 +08:00
|
|
|
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
|
|
|
|
/*EnteringContext=*/false))
|
2010-02-26 16:45:28 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (SS.isSet() && Tok.isNot(tok::identifier)) {
|
2008-11-09 00:45:02 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-09-11 08:21:41 +08:00
|
|
|
// Must have either 'enum name' or 'enum {...}'.
|
2011-02-22 10:55:24 +08:00
|
|
|
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) &&
|
2012-03-12 16:56:40 +08:00
|
|
|
!(AllowFixedUnderlyingType && Tok.is(tok::colon))) {
|
2008-09-11 08:21:41 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident_lbrace);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-09-11 08:21:41 +08:00
|
|
|
// 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
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-01-10 09:33:14 +08:00
|
|
|
if (!Name && ScopedEnumKWLoc.isValid()) {
|
2010-10-09 07:50:27 +08:00
|
|
|
// C++0x 7.2p2: The optional identifier shall not be omitted in the
|
|
|
|
// declaration of a scoped enumeration.
|
|
|
|
Diag(Tok, diag::err_scoped_enum_missing_identifier);
|
2012-01-10 09:33:14 +08:00
|
|
|
ScopedEnumKWLoc = SourceLocation();
|
2010-12-04 02:54:17 +08:00
|
|
|
IsScopedUsingClassTag = false;
|
2010-10-09 07:50:27 +08:00
|
|
|
}
|
|
|
|
|
2012-05-07 14:16:58 +08:00
|
|
|
// Okay, end the suppression area. We'll decide whether to emit the
|
|
|
|
// diagnostics in a second.
|
|
|
|
if (shouldDelayDiagsInTag)
|
|
|
|
diagsFromTag.done();
|
2012-03-23 11:33:32 +08:00
|
|
|
|
2010-10-09 07:50:27 +08:00
|
|
|
TypeResult BaseType;
|
|
|
|
|
2010-12-02 01:42:47 +08:00
|
|
|
// Parse the fixed underlying type.
|
2011-02-22 10:55:24 +08:00
|
|
|
if (AllowFixedUnderlyingType && Tok.is(tok::colon)) {
|
2010-12-02 01:42:47 +08:00
|
|
|
bool PossibleBitfield = false;
|
|
|
|
if (getCurScope()->getFlags() & Scope::ClassScope) {
|
|
|
|
// If we're in class scope, this can either be an enum declaration with
|
|
|
|
// an underlying type, or a declaration of a bitfield member. We try to
|
|
|
|
// use a simple disambiguation scheme first to catch the common cases
|
|
|
|
// (integer literal, sizeof); if it's still ambiguous, we then consider
|
|
|
|
// anything that's a simple-type-specifier followed by '(' as an
|
|
|
|
// expression. This suffices because function types are not valid
|
|
|
|
// underlying types anyway.
|
|
|
|
TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind());
|
|
|
|
// If the next token starts an expression, we know we're parsing a
|
|
|
|
// bit-field. This is the common case.
|
|
|
|
if (TPR == TPResult::True())
|
|
|
|
PossibleBitfield = true;
|
|
|
|
// If the next token starts a type-specifier-seq, it may be either a
|
|
|
|
// a fixed underlying type or the start of a function-style cast in C++;
|
|
|
|
// lookahead one more token to see if it's obvious that we have a
|
|
|
|
// fixed underlying type.
|
|
|
|
else if (TPR == TPResult::False() &&
|
|
|
|
GetLookAheadToken(2).getKind() == tok::semi) {
|
|
|
|
// Consume the ':'.
|
|
|
|
ConsumeToken();
|
|
|
|
} else {
|
|
|
|
// We have the start of a type-specifier-seq, so we have to perform
|
|
|
|
// tentative parsing to determine whether we have an expression or a
|
|
|
|
// type.
|
|
|
|
TentativeParsingAction TPA(*this);
|
|
|
|
|
|
|
|
// Consume the ':'.
|
|
|
|
ConsumeToken();
|
2012-02-23 09:36:12 +08:00
|
|
|
|
|
|
|
// If we see a type specifier followed by an open-brace, we have an
|
|
|
|
// ambiguity between an underlying type and a C++11 braced
|
|
|
|
// function-style cast. Resolve this by always treating it as an
|
|
|
|
// underlying type.
|
|
|
|
// FIXME: The standard is not entirely clear on how to disambiguate in
|
|
|
|
// this case.
|
2012-03-11 15:00:24 +08:00
|
|
|
if ((getLangOpts().CPlusPlus &&
|
2012-02-23 09:36:12 +08:00
|
|
|
isCXXDeclarationSpecifier(TPResult::True()) != TPResult::True()) ||
|
2012-03-11 15:00:24 +08:00
|
|
|
(!getLangOpts().CPlusPlus && !isDeclarationSpecifier(true))) {
|
2010-12-02 01:42:47 +08:00
|
|
|
// We'll parse this as a bitfield later.
|
|
|
|
PossibleBitfield = true;
|
|
|
|
TPA.Revert();
|
|
|
|
} else {
|
|
|
|
// We have a type-specifier-seq.
|
|
|
|
TPA.Commit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Consume the ':'.
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!PossibleBitfield) {
|
|
|
|
SourceRange Range;
|
|
|
|
BaseType = ParseTypeName(&Range);
|
2011-02-23 04:32:04 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().CPlusPlus0x && !getLangOpts().ObjC2)
|
2011-02-23 04:32:04 +08:00
|
|
|
Diag(StartLoc, diag::ext_ms_enum_fixed_underlying_type)
|
|
|
|
<< Range;
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus0x)
|
2011-10-15 13:09:34 +08:00
|
|
|
Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type);
|
2010-12-02 01:42:47 +08:00
|
|
|
}
|
2010-10-09 07:50:27 +08:00
|
|
|
}
|
|
|
|
|
2012-01-10 09:33:14 +08:00
|
|
|
// There are four options here. If we have 'friend enum foo;' then this is a
|
|
|
|
// friend declaration, and cannot have an accompanying definition. 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.
|
2008-09-11 08:21:41 +08:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
2010-08-27 07:41:50 +08:00
|
|
|
Sema::TagUseKind TUK;
|
2012-05-07 14:16:58 +08:00
|
|
|
if (!AllowDeclaration) {
|
2012-03-12 16:56:40 +08:00
|
|
|
TUK = Sema::TUK_Reference;
|
2012-05-07 14:16:58 +08:00
|
|
|
} else if (Tok.is(tok::l_brace)) {
|
|
|
|
if (DS.isFriendSpecified()) {
|
|
|
|
Diag(Tok.getLocation(), diag::err_friend_decl_defines_type)
|
|
|
|
<< SourceRange(DS.getFriendSpecLoc());
|
|
|
|
ConsumeBrace();
|
|
|
|
SkipUntil(tok::r_brace);
|
|
|
|
TUK = Sema::TUK_Friend;
|
|
|
|
} else {
|
|
|
|
TUK = Sema::TUK_Definition;
|
|
|
|
}
|
|
|
|
} else if (Tok.is(tok::semi) && DSC != DSC_type_specifier) {
|
|
|
|
TUK = (DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration);
|
|
|
|
} else {
|
2010-08-27 07:41:50 +08:00
|
|
|
TUK = Sema::TUK_Reference;
|
2012-05-07 14:16:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If this is an elaborated type specifier, and we delayed
|
|
|
|
// diagnostics before, just merge them into the current pool.
|
|
|
|
if (TUK == Sema::TUK_Reference && shouldDelayDiagsInTag) {
|
|
|
|
diagsFromTag.redelay();
|
|
|
|
}
|
2012-03-23 11:33:32 +08:00
|
|
|
|
|
|
|
MultiTemplateParamsArg TParams;
|
2010-05-04 01:48:54 +08:00
|
|
|
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
|
2010-08-27 07:41:50 +08:00
|
|
|
TUK != Sema::TUK_Reference) {
|
2012-03-23 11:33:32 +08:00
|
|
|
if (!getLangOpts().CPlusPlus0x || !SS.isSet()) {
|
|
|
|
// Skip the rest of this declarator, up until the comma or semicolon.
|
|
|
|
Diag(Tok, diag::err_enum_template);
|
|
|
|
SkipUntil(tok::comma, true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
|
|
|
|
// Enumerations can't be explicitly instantiated.
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
Diag(StartLoc, diag::err_explicit_instantiation_enum);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(TemplateInfo.TemplateParams && "no template parameters");
|
|
|
|
TParams = MultiTemplateParamsArg(TemplateInfo.TemplateParams->data(),
|
|
|
|
TemplateInfo.TemplateParams->size());
|
2010-05-04 01:48:54 +08:00
|
|
|
}
|
2012-03-23 11:33:32 +08:00
|
|
|
|
2011-02-22 10:55:24 +08:00
|
|
|
if (!Name && TUK != Sema::TUK_Definition) {
|
|
|
|
Diag(Tok, diag::err_enumerator_unnamed_no_def);
|
2012-03-23 11:33:32 +08:00
|
|
|
|
2011-02-22 10:55:24 +08:00
|
|
|
// Skip the rest of this declarator, up until the comma or semicolon.
|
|
|
|
SkipUntil(tok::comma, true);
|
|
|
|
return;
|
|
|
|
}
|
2012-03-23 11:33:32 +08:00
|
|
|
|
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-09-11 12:59:25 +08:00
|
|
|
bool IsDependent = false;
|
2010-04-25 00:38:41 +08:00
|
|
|
const char *PrevSpec = 0;
|
|
|
|
unsigned DiagID;
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK,
|
2010-12-24 10:08:15 +08:00
|
|
|
StartLoc, SS, Name, NameLoc, attrs.getList(),
|
2012-03-23 11:33:32 +08:00
|
|
|
AS, DS.getModulePrivateSpecLoc(), TParams,
|
2012-01-10 09:33:14 +08:00
|
|
|
Owned, IsDependent, ScopedEnumKWLoc,
|
2010-12-04 02:54:17 +08:00
|
|
|
IsScopedUsingClassTag, BaseType);
|
2010-10-09 07:50:27 +08:00
|
|
|
|
2010-04-25 00:38:41 +08:00
|
|
|
if (IsDependent) {
|
|
|
|
// This enum has a dependent nested-name-specifier. Handle it as a
|
|
|
|
// dependent tag.
|
|
|
|
if (!Name) {
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
Diag(Tok, diag::err_expected_type_name_after_typename);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-07-03 01:43:08 +08:00
|
|
|
TypeResult Type = Actions.ActOnDependentTag(getCurScope(), DeclSpec::TST_enum,
|
2010-04-25 00:38:41 +08:00
|
|
|
TUK, SS, Name, StartLoc,
|
|
|
|
NameLoc);
|
|
|
|
if (Type.isInvalid()) {
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-03-17 04:16:18 +08:00
|
|
|
if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc,
|
|
|
|
NameLoc.isValid() ? NameLoc : StartLoc,
|
|
|
|
PrevSpec, DiagID, Type.get()))
|
2010-04-25 00:38:41 +08:00
|
|
|
Diag(StartLoc, DiagID) << PrevSpec;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-21 17:40:31 +08:00
|
|
|
if (!TagDecl) {
|
2010-04-25 00:38:41 +08:00
|
|
|
// The action failed to produce an enumeration tag. If this is a
|
|
|
|
// definition, consume the entire definition.
|
2012-03-12 16:56:40 +08:00
|
|
|
if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
|
2010-04-25 00:38:41 +08:00
|
|
|
ConsumeBrace();
|
|
|
|
SkipUntil(tok::r_brace);
|
|
|
|
}
|
|
|
|
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
return;
|
|
|
|
}
|
2012-01-10 09:33:14 +08:00
|
|
|
|
2012-03-12 16:56:40 +08:00
|
|
|
if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
|
2012-05-07 14:16:58 +08:00
|
|
|
ParseEnumBody(StartLoc, TagDecl);
|
2012-01-10 09:33:14 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-03-17 04:16:18 +08:00
|
|
|
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
|
|
|
|
NameLoc.isValid() ? NameLoc : StartLoc,
|
|
|
|
PrevSpec, DiagID, TagDecl, 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
|
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *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);
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnTagStartDefinition(getCurScope(), EnumDecl);
|
2009-01-06 03:45:36 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_brace);
|
|
|
|
T.consumeOpen();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-28 01:24:30 +08:00
|
|
|
// C does not allow an empty enumerator-list, C++ does [dcl.enum].
|
2012-03-11 15:00:24 +08:00
|
|
|
if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus)
|
2010-05-29 06:23:22 +08:00
|
|
|
Diag(Tok, diag::error_empty_enum);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 32> EnumConstantDecls;
|
2007-01-25 15:29:02 +08:00
|
|
|
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *LastEnumConstDecl = 0;
|
2009-09-09 23:08:12 +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();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-10-23 07:36:17 +08:00
|
|
|
// If attributes exist after the enumerator, parse them.
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseGNUAttributes(attrs);
|
2010-10-23 07:36:17 +08:00
|
|
|
|
2007-01-25 15:29:02 +08:00
|
|
|
SourceLocation EqualLoc;
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult AssignedVal;
|
2012-05-07 14:16:41 +08:00
|
|
|
ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
|
2011-12-09 09:15:54 +08:00
|
|
|
|
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
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-01-25 15:29:02 +08:00
|
|
|
// Install the enumerator constant into EnumDecl.
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *EnumConstDecl = Actions.ActOnEnumConstant(getCurScope(), EnumDecl,
|
|
|
|
LastEnumConstDecl,
|
|
|
|
IdentLoc, Ident,
|
2010-12-24 10:08:15 +08:00
|
|
|
attrs.getList(), EqualLoc,
|
2010-08-21 17:40:31 +08:00
|
|
|
AssignedVal.release());
|
2011-12-09 09:15:54 +08:00
|
|
|
PD.complete(EnumConstDecl);
|
|
|
|
|
2007-06-11 09:28:17 +08:00
|
|
|
EnumConstantDecls.push_back(EnumConstDecl);
|
|
|
|
LastEnumConstDecl = EnumConstDecl;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-09-07 22:51:08 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
|
|
|
// We're missing a comma between enumerators.
|
|
|
|
SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation);
|
|
|
|
Diag(Loc, diag::err_enumerator_list_missing_comma)
|
|
|
|
<< FixItHint::CreateInsertion(Loc, ", ");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
2011-10-15 13:09:34 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus0x)
|
2011-10-15 13:09:34 +08:00
|
|
|
Diag(CommaLoc, diag::ext_enumerator_list_comma)
|
2012-03-11 15:00:24 +08:00
|
|
|
<< getLangOpts().CPlusPlus
|
2011-10-15 13:09:34 +08:00
|
|
|
<< FixItHint::CreateRemoval(CommaLoc);
|
2012-03-11 15:00:24 +08:00
|
|
|
else if (getLangOpts().CPlusPlus0x)
|
2011-10-15 13:09:34 +08:00
|
|
|
Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma)
|
|
|
|
<< FixItHint::CreateRemoval(CommaLoc);
|
|
|
|
}
|
2006-08-13 08:12:11 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-01-25 15:29:02 +08:00
|
|
|
// Eat the }.
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2007-01-25 15:29:02 +08:00
|
|
|
|
|
|
|
// If attributes exist after the identifier list, parse them.
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseGNUAttributes(attrs);
|
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
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
Actions.ActOnEnumBody(StartLoc, T.getOpenLocation(), T.getCloseLocation(),
|
|
|
|
EnumDecl, EnumConstantDecls.data(),
|
|
|
|
EnumConstantDecls.size(), getCurScope(),
|
|
|
|
attrs.getList());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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();
|
2011-10-13 00:37:45 +08:00
|
|
|
Actions.ActOnTagFinishDefinition(getCurScope(), EnumDecl,
|
|
|
|
T.getCloseLocation());
|
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;
|
2011-03-19 06:38:29 +08:00
|
|
|
|
|
|
|
// type-qualifier only in OpenCL
|
|
|
|
case tok::kw_private:
|
2012-03-11 15:00:24 +08:00
|
|
|
return getLangOpts().OpenCL;
|
2011-03-19 06:38:29 +08:00
|
|
|
|
2008-02-12 07:15:56 +08:00
|
|
|
// type-qualifier
|
|
|
|
case tok::kw_const:
|
|
|
|
case tok::kw_volatile:
|
|
|
|
case tok::kw_restrict:
|
2011-03-19 06:38:29 +08:00
|
|
|
case tok::kw___private:
|
|
|
|
case tok::kw___local:
|
|
|
|
case tok::kw___global:
|
|
|
|
case tok::kw___constant:
|
|
|
|
case tok::kw___read_only:
|
|
|
|
case tok::kw___read_write:
|
|
|
|
case tok::kw___write_only:
|
2008-02-12 07:15:56 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-01 02:18:36 +08:00
|
|
|
/// isKnownToBeTypeSpecifier - Return true if we know that the specified token
|
|
|
|
/// is definitely a type-specifier. Return false if it isn't part of a type
|
|
|
|
/// specifier or if we're not sure.
|
|
|
|
bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const {
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default: return false;
|
|
|
|
// type-specifiers
|
|
|
|
case tok::kw_short:
|
|
|
|
case tok::kw_long:
|
2011-04-28 09:59:37 +08:00
|
|
|
case tok::kw___int64:
|
2012-04-04 14:24:32 +08:00
|
|
|
case tok::kw___int128:
|
2010-03-01 02:18:36 +08:00
|
|
|
case tok::kw_signed:
|
|
|
|
case tok::kw_unsigned:
|
|
|
|
case tok::kw__Complex:
|
|
|
|
case tok::kw__Imaginary:
|
|
|
|
case tok::kw_void:
|
|
|
|
case tok::kw_char:
|
|
|
|
case tok::kw_wchar_t:
|
|
|
|
case tok::kw_char16_t:
|
|
|
|
case tok::kw_char32_t:
|
|
|
|
case tok::kw_int:
|
2011-10-15 07:23:15 +08:00
|
|
|
case tok::kw_half:
|
2010-03-01 02:18:36 +08:00
|
|
|
case tok::kw_float:
|
|
|
|
case tok::kw_double:
|
|
|
|
case tok::kw_bool:
|
|
|
|
case tok::kw__Bool:
|
|
|
|
case tok::kw__Decimal32:
|
|
|
|
case tok::kw__Decimal64:
|
|
|
|
case tok::kw__Decimal128:
|
|
|
|
case tok::kw___vector:
|
|
|
|
|
|
|
|
// struct-or-union-specifier (C99) or class-specifier (C++)
|
|
|
|
case tok::kw_class:
|
|
|
|
case tok::kw_struct:
|
|
|
|
case tok::kw_union:
|
|
|
|
// enum-specifier
|
|
|
|
case tok::kw_enum:
|
|
|
|
|
|
|
|
// typedef-name
|
|
|
|
case tok::annot_typename:
|
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
2009-01-05 07:41:41 +08:00
|
|
|
case tok::identifier: // foo::bar
|
2010-02-05 08:12:22 +08:00
|
|
|
if (TryAltiVecVectorToken())
|
|
|
|
return true;
|
|
|
|
// Fall through.
|
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())
|
2010-02-26 16:45:28 +08:00
|
|
|
return true;
|
|
|
|
if (Tok.is(tok::identifier))
|
|
|
|
return false;
|
|
|
|
return isTypeSpecifierQualifier();
|
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;
|
|
|
|
|
|
|
|
if (TryAnnotateTypeOrScopeToken())
|
2010-02-26 16:45:28 +08:00
|
|
|
return true;
|
|
|
|
return isTypeSpecifierQualifier();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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:
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-08-11 07:56:11 +08:00
|
|
|
// type-specifiers
|
|
|
|
case tok::kw_short:
|
|
|
|
case tok::kw_long:
|
2011-04-28 09:59:37 +08:00
|
|
|
case tok::kw___int64:
|
2012-04-04 14:24:32 +08:00
|
|
|
case tok::kw___int128:
|
2006-08-11 07:56:11 +08:00
|
|
|
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:
|
2011-10-15 07:23:15 +08:00
|
|
|
case tok::kw_half:
|
2006-08-11 07:56:11 +08:00
|
|
|
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:
|
2010-02-05 08:12:22 +08:00
|
|
|
case tok::kw___vector:
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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:
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-08-11 07:56:11 +08:00
|
|
|
// 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;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 08:25:30 +08:00
|
|
|
// GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
|
|
|
|
case tok::less:
|
2012-03-11 15:00:24 +08:00
|
|
|
return getLangOpts().ObjC1;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-25 22:16:32 +08:00
|
|
|
case tok::kw___cdecl:
|
|
|
|
case tok::kw___stdcall:
|
|
|
|
case tok::kw___fastcall:
|
2010-05-19 00:57:00 +08:00
|
|
|
case tok::kw___thiscall:
|
2009-06-09 07:27:34 +08:00
|
|
|
case tok::kw___w64:
|
|
|
|
case tok::kw___ptr64:
|
2011-08-25 08:36:46 +08:00
|
|
|
case tok::kw___ptr32:
|
2010-09-03 09:29:35 +08:00
|
|
|
case tok::kw___pascal:
|
2011-08-18 17:59:55 +08:00
|
|
|
case tok::kw___unaligned:
|
2011-03-19 06:38:29 +08:00
|
|
|
|
|
|
|
case tok::kw___private:
|
|
|
|
case tok::kw___local:
|
|
|
|
case tok::kw___global:
|
|
|
|
case tok::kw___constant:
|
|
|
|
case tok::kw___read_only:
|
|
|
|
case tok::kw___read_write:
|
|
|
|
case tok::kw___write_only:
|
|
|
|
|
2009-06-09 07:27:34 +08:00
|
|
|
return true;
|
2011-03-19 06:38:29 +08:00
|
|
|
|
|
|
|
case tok::kw_private:
|
2012-03-11 15:00:24 +08:00
|
|
|
return getLangOpts().OpenCL;
|
2011-10-07 07:00:33 +08:00
|
|
|
|
2011-12-24 01:00:35 +08:00
|
|
|
// C11 _Atomic()
|
2011-10-07 07:00:33 +08:00
|
|
|
case tok::kw__Atomic:
|
|
|
|
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.
|
2010-09-16 09:51:54 +08:00
|
|
|
///
|
|
|
|
/// \param DisambiguatingWithExpression True to indicate that the purpose of
|
|
|
|
/// this check is to disambiguate between an expression and a declaration.
|
|
|
|
bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
|
2006-08-07 01:24:14 +08:00
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default: return false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-03-19 06:38:29 +08:00
|
|
|
case tok::kw_private:
|
2012-03-11 15:00:24 +08:00
|
|
|
return getLangOpts().OpenCL;
|
2011-03-19 06:38:29 +08:00
|
|
|
|
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.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().ObjC1 && NextToken().is(tok::period))
|
2009-03-10 05:12:44 +08:00
|
|
|
return false;
|
2010-02-05 08:12:22 +08:00
|
|
|
if (TryAltiVecVectorToken())
|
|
|
|
return true;
|
|
|
|
// Fall through.
|
2011-12-04 13:04:18 +08:00
|
|
|
case tok::kw_decltype: // decltype(T())::type
|
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())
|
2010-02-26 16:45:28 +08:00
|
|
|
return true;
|
|
|
|
if (Tok.is(tok::identifier))
|
|
|
|
return false;
|
2010-09-16 09:51:54 +08:00
|
|
|
|
|
|
|
// If we're in Objective-C and we have an Objective-C class type followed
|
|
|
|
// by an identifier and then either ':' or ']', in a place where an
|
|
|
|
// expression is permitted, then this is probably a class message send
|
|
|
|
// missing the initial '['. In this case, we won't consider this to be
|
|
|
|
// the start of a declaration.
|
|
|
|
if (DisambiguatingWithExpression &&
|
|
|
|
isStartOfObjCClassMessageMissingOpenBracket())
|
|
|
|
return false;
|
|
|
|
|
2010-02-26 16:45:28 +08:00
|
|
|
return isDeclarationSpecifier();
|
|
|
|
|
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;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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())
|
2010-02-26 16:45:28 +08:00
|
|
|
return true;
|
|
|
|
return isDeclarationSpecifier();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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:
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-09-09 10:06:17 +08:00
|
|
|
// Modules
|
|
|
|
case tok::kw___module_private__:
|
|
|
|
|
2006-08-07 01:24:14 +08:00
|
|
|
// type-specifiers
|
|
|
|
case tok::kw_short:
|
|
|
|
case tok::kw_long:
|
2011-04-28 09:59:37 +08:00
|
|
|
case tok::kw___int64:
|
2012-04-04 14:24:32 +08:00
|
|
|
case tok::kw___int128:
|
2006-08-07 01:24:14 +08:00
|
|
|
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:
|
2011-10-15 07:23:15 +08:00
|
|
|
case tok::kw_half:
|
2006-08-07 01:24:14 +08:00
|
|
|
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:
|
2010-02-05 08:12:22 +08:00
|
|
|
case tok::kw___vector:
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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:
|
2009-09-09 23:08:12 +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
|
|
|
|
2011-04-15 08:35:57 +08:00
|
|
|
// static_assert-declaration
|
|
|
|
case tok::kw__Static_assert:
|
|
|
|
|
2007-08-10 01:01:07 +08:00
|
|
|
// GNU typeof support.
|
|
|
|
case tok::kw_typeof:
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-10 01:01:07 +08:00
|
|
|
// GNU attributes.
|
2007-08-10 00:40:21 +08:00
|
|
|
case tok::kw___attribute:
|
2008-07-26 11:38:44 +08:00
|
|
|
return true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-06-19 16:02:06 +08:00
|
|
|
// C++0x decltype.
|
2011-12-04 13:04:18 +08:00
|
|
|
case tok::annot_decltype:
|
2011-06-19 16:02:06 +08:00
|
|
|
return true;
|
|
|
|
|
2011-12-24 01:00:35 +08:00
|
|
|
// C11 _Atomic()
|
2011-10-07 07:00:33 +08:00
|
|
|
case tok::kw__Atomic:
|
|
|
|
return true;
|
|
|
|
|
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:
|
2012-03-11 15:00:24 +08:00
|
|
|
return getLangOpts().ObjC1;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-04-27 13:41:15 +08:00
|
|
|
// typedef-name
|
|
|
|
case tok::annot_typename:
|
|
|
|
return !DisambiguatingWithExpression ||
|
|
|
|
!isStartOfObjCClassMessageMissingOpenBracket();
|
|
|
|
|
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:
|
2010-05-19 00:57:00 +08:00
|
|
|
case tok::kw___thiscall:
|
2009-06-09 07:27:34 +08:00
|
|
|
case tok::kw___w64:
|
|
|
|
case tok::kw___ptr64:
|
2011-08-25 08:36:46 +08:00
|
|
|
case tok::kw___ptr32:
|
2009-06-09 07:27:34 +08:00
|
|
|
case tok::kw___forceinline:
|
2010-09-03 09:29:35 +08:00
|
|
|
case tok::kw___pascal:
|
2011-08-18 17:59:55 +08:00
|
|
|
case tok::kw___unaligned:
|
2011-03-19 06:38:29 +08:00
|
|
|
|
|
|
|
case tok::kw___private:
|
|
|
|
case tok::kw___local:
|
|
|
|
case tok::kw___global:
|
|
|
|
case tok::kw___constant:
|
|
|
|
case tok::kw___read_only:
|
|
|
|
case tok::kw___read_write:
|
|
|
|
case tok::kw___write_only:
|
|
|
|
|
2009-06-09 07:27:34 +08:00
|
|
|
return true;
|
2006-08-07 01:24:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-14 01:31:36 +08:00
|
|
|
bool Parser::isConstructorDeclarator() {
|
|
|
|
TentativeParsingAction TPA(*this);
|
|
|
|
|
|
|
|
// Parse the C++ scope specifier.
|
|
|
|
CXXScopeSpec SS;
|
2011-11-08 01:33:42 +08:00
|
|
|
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
|
|
|
|
/*EnteringContext=*/true)) {
|
2010-02-26 16:45:28 +08:00
|
|
|
TPA.Revert();
|
|
|
|
return false;
|
|
|
|
}
|
2010-01-14 01:31:36 +08:00
|
|
|
|
|
|
|
// Parse the constructor name.
|
|
|
|
if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) {
|
|
|
|
// We already know that we have a constructor name; just consume
|
|
|
|
// the token.
|
|
|
|
ConsumeToken();
|
|
|
|
} else {
|
|
|
|
TPA.Revert();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-03-28 07:05:05 +08:00
|
|
|
// Current class name must be followed by a left parenthesis.
|
2010-01-14 01:31:36 +08:00
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
|
|
|
TPA.Revert();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ConsumeParen();
|
|
|
|
|
2012-03-28 07:05:05 +08:00
|
|
|
// A right parenthesis, or ellipsis followed by a right parenthesis signals
|
|
|
|
// that we have a constructor.
|
|
|
|
if (Tok.is(tok::r_paren) ||
|
|
|
|
(Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren))) {
|
2010-01-14 01:31:36 +08:00
|
|
|
TPA.Revert();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we need to, enter the specified scope.
|
|
|
|
DeclaratorScopeObj DeclScopeObj(*this, SS);
|
2010-07-03 01:43:08 +08:00
|
|
|
if (SS.isSet() && Actions.ShouldEnterDeclaratorScope(getCurScope(), SS))
|
2010-01-14 01:31:36 +08:00
|
|
|
DeclScopeObj.EnterDeclaratorScope();
|
|
|
|
|
2011-01-31 12:54:32 +08:00
|
|
|
// Optionally skip Microsoft attributes.
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes Attrs(AttrFactory);
|
2011-01-31 12:54:32 +08:00
|
|
|
MaybeParseMicrosoftAttributes(Attrs);
|
|
|
|
|
2010-01-14 01:31:36 +08:00
|
|
|
// Check whether the next token(s) are part of a declaration
|
|
|
|
// specifier, in which case we have the start of a parameter and,
|
|
|
|
// therefore, we know that this is a constructor.
|
2012-03-27 08:56:56 +08:00
|
|
|
bool IsConstructor = false;
|
|
|
|
if (isDeclarationSpecifier())
|
|
|
|
IsConstructor = true;
|
|
|
|
else if (Tok.is(tok::identifier) ||
|
|
|
|
(Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) {
|
|
|
|
// We've seen "C ( X" or "C ( X::Y", but "X" / "X::Y" is not a type.
|
|
|
|
// This might be a parenthesized member name, but is more likely to
|
|
|
|
// be a constructor declaration with an invalid argument type. Keep
|
|
|
|
// looking.
|
|
|
|
if (Tok.is(tok::annot_cxxscope))
|
|
|
|
ConsumeToken();
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// If this is not a constructor, we must be parsing a declarator,
|
2012-03-27 09:42:32 +08:00
|
|
|
// which must have one of the following syntactic forms (see the
|
|
|
|
// grammar extract at the start of ParseDirectDeclarator):
|
2012-03-27 08:56:56 +08:00
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::l_paren:
|
|
|
|
// C(X ( int));
|
|
|
|
case tok::l_square:
|
|
|
|
// C(X [ 5]);
|
|
|
|
// C(X [ [attribute]]);
|
|
|
|
case tok::coloncolon:
|
|
|
|
// C(X :: Y);
|
|
|
|
// C(X :: *p);
|
|
|
|
case tok::r_paren:
|
|
|
|
// C(X )
|
|
|
|
// Assume this isn't a constructor, rather than assuming it's a
|
|
|
|
// constructor with an unnamed parameter of an ill-formed type.
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
IsConstructor = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-14 01:31:36 +08:00
|
|
|
TPA.Revert();
|
|
|
|
return IsConstructor;
|
|
|
|
}
|
2006-08-04 12:39:53 +08:00
|
|
|
|
2006-07-31 13:13:43 +08:00
|
|
|
/// ParseTypeQualifierListOpt
|
2010-09-03 09:29:35 +08:00
|
|
|
/// type-qualifier-list: [C99 6.7.5]
|
|
|
|
/// type-qualifier
|
|
|
|
/// [vendor] attributes
|
|
|
|
/// [ only if VendorAttributesAllowed=true ]
|
|
|
|
/// type-qualifier-list type-qualifier
|
|
|
|
/// [vendor] type-qualifier-list attributes
|
|
|
|
/// [ only if VendorAttributesAllowed=true ]
|
|
|
|
/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq
|
|
|
|
/// [ only if CXX0XAttributesAllowed=true ]
|
|
|
|
/// Note: vendor can be GNU, MS, etc.
|
2006-07-31 13:13:43 +08:00
|
|
|
///
|
2010-09-03 09:29:35 +08:00
|
|
|
void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
|
|
|
|
bool VendorAttributesAllowed,
|
2012-04-10 11:25:07 +08:00
|
|
|
bool CXX11AttributesAllowed) {
|
|
|
|
if (getLangOpts().CPlusPlus0x && CXX11AttributesAllowed &&
|
2012-04-10 09:32:12 +08:00
|
|
|
isCXX11AttributeSpecifier()) {
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributesWithRange attrs(AttrFactory);
|
2012-04-10 11:25:07 +08:00
|
|
|
ParseCXX11Attributes(attrs);
|
2012-04-10 09:32:12 +08:00
|
|
|
DS.takeAttributesFrom(attrs);
|
2009-11-21 16:43:09 +08:00
|
|
|
}
|
2011-03-12 19:17:06 +08:00
|
|
|
|
|
|
|
SourceLocation EndLoc;
|
|
|
|
|
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()) {
|
2010-08-28 01:35:51 +08:00
|
|
|
case tok::code_completion:
|
|
|
|
Actions.CodeCompleteTypeQualifiers(DS);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2010-08-28 01:35:51 +08:00
|
|
|
|
2006-07-31 13:13:43 +08:00
|
|
|
case tok::kw_const:
|
2009-08-04 04:12:06 +08:00
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID,
|
2012-03-11 15:00:24 +08:00
|
|
|
getLangOpts());
|
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,
|
2012-03-11 15:00:24 +08:00
|
|
|
getLangOpts());
|
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,
|
2012-03-11 15:00:24 +08:00
|
|
|
getLangOpts());
|
2006-07-31 13:13:43 +08:00
|
|
|
break;
|
2011-03-19 06:38:29 +08:00
|
|
|
|
|
|
|
// OpenCL qualifiers:
|
|
|
|
case tok::kw_private:
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().OpenCL)
|
2011-03-19 06:38:29 +08:00
|
|
|
goto DoneWithTypeQuals;
|
|
|
|
case tok::kw___private:
|
|
|
|
case tok::kw___global:
|
|
|
|
case tok::kw___local:
|
|
|
|
case tok::kw___constant:
|
|
|
|
case tok::kw___read_only:
|
|
|
|
case tok::kw___write_only:
|
|
|
|
case tok::kw___read_write:
|
|
|
|
ParseOpenCLQualifiers(DS);
|
|
|
|
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:
|
2011-08-25 08:36:46 +08:00
|
|
|
case tok::kw___ptr32:
|
2008-12-25 22:16:32 +08:00
|
|
|
case tok::kw___cdecl:
|
|
|
|
case tok::kw___stdcall:
|
|
|
|
case tok::kw___fastcall:
|
2010-05-19 00:57:00 +08:00
|
|
|
case tok::kw___thiscall:
|
2011-08-18 17:59:55 +08:00
|
|
|
case tok::kw___unaligned:
|
2010-09-03 09:29:35 +08:00
|
|
|
if (VendorAttributesAllowed) {
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseMicrosoftTypeAttributes(DS.getAttributes());
|
2009-06-09 07:27:34 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
goto DoneWithTypeQuals;
|
2010-09-03 09:29:35 +08:00
|
|
|
case tok::kw___pascal:
|
|
|
|
if (VendorAttributesAllowed) {
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseBorlandTypeAttributes(DS.getAttributes());
|
2010-09-03 09:29:35 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
goto DoneWithTypeQuals;
|
2006-08-15 12:50:22 +08:00
|
|
|
case tok::kw___attribute:
|
2010-09-03 09:29:35 +08:00
|
|
|
if (VendorAttributesAllowed) {
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseGNUAttributes(DS.getAttributes());
|
2008-12-18 15:02:59 +08:00
|
|
|
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);
|
2011-03-12 19:17:06 +08:00
|
|
|
if (EndLoc.isValid())
|
|
|
|
DS.SetRangeEnd(EndLoc);
|
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
|
|
|
}
|
2011-03-12 19:17:06 +08:00
|
|
|
EndLoc = 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
|
|
|
}
|
|
|
|
|
2012-03-29 09:16:42 +08:00
|
|
|
static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang) {
|
|
|
|
if (Kind == tok::star || Kind == tok::caret)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// We parse rvalue refs in C++03, because otherwise the errors are scary.
|
|
|
|
if (!Lang.CPlusPlus)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return Kind == tok::amp || Kind == tok::ampamp;
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
///
|
2011-10-20 05:33:05 +08:00
|
|
|
/// If the grammar of this construct is extended, matching changes must also be
|
2012-03-27 09:42:32 +08:00
|
|
|
/// made to TryParseDeclarator and MightBeDeclarator, and possibly to
|
|
|
|
/// isConstructorDeclarator.
|
2011-10-20 05:33:05 +08:00
|
|
|
///
|
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) {
|
2009-08-26 22:27:30 +08:00
|
|
|
if (Diags.hasAllExtensionsSilenced())
|
|
|
|
D.setExtension();
|
2010-08-24 02:23:48 +08:00
|
|
|
|
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.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus &&
|
2009-03-25 01:04:48 +08:00
|
|
|
(Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||
|
|
|
|
Tok.is(tok::annot_cxxscope))) {
|
2011-11-08 01:33:42 +08:00
|
|
|
bool EnteringContext = D.getContext() == Declarator::FileContext ||
|
|
|
|
D.getContext() == Declarator::MemberContext;
|
2009-01-25 05:16:55 +08:00
|
|
|
CXXScopeSpec SS;
|
2011-11-08 01:33:42 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext);
|
2010-02-26 16:45:28 +08:00
|
|
|
|
2010-04-08 07:29:58 +08:00
|
|
|
if (SS.isNotEmpty()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
if (Tok.isNot(tok::star)) {
|
2009-01-25 05:16:55 +08:00
|
|
|
// 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);
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2009-01-25 05:16:55 +08:00
|
|
|
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(),
|
2011-03-24 19:26:52 +08:00
|
|
|
Loc),
|
|
|
|
DS.getAttributes(),
|
2009-02-10 02:23:29 +08:00
|
|
|
/* 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.
|
2012-03-29 09:16:42 +08:00
|
|
|
if (!isPtrOperatorToken(Kind, getLangOpts())) {
|
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.
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2009-01-25 05:16:55 +08:00
|
|
|
|
2012-04-10 09:32:12 +08:00
|
|
|
// FIXME: GNU attributes are not allowed here in a new-type-id.
|
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,
|
2011-02-24 02:51:59 +08:00
|
|
|
DS.getConstSpecLoc(),
|
|
|
|
DS.getVolatileSpecLoc(),
|
2011-03-24 19:26:52 +08:00
|
|
|
DS.getRestrictSpecLoc()),
|
|
|
|
DS.getAttributes(),
|
2009-02-10 02:23:29 +08:00
|
|
|
SourceLocation());
|
2008-08-28 00:04:49 +08:00
|
|
|
else
|
|
|
|
// Remember that we parsed a Block type, and remember the type-quals.
|
2009-09-09 23:08:12 +08:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(),
|
2011-03-24 19:26:52 +08:00
|
|
|
Loc),
|
|
|
|
DS.getAttributes(),
|
2009-02-10 02:23:29 +08:00
|
|
|
SourceLocation());
|
2007-05-27 18:15:43 +08:00
|
|
|
} else {
|
|
|
|
// Is a reference
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2007-06-03 07:28:54 +08:00
|
|
|
|
2009-03-23 08:00:23 +08:00
|
|
|
// Complain about rvalue references in C++03, but then go on and build
|
|
|
|
// the declarator.
|
2011-10-15 13:09:34 +08:00
|
|
|
if (Kind == tok::ampamp)
|
2012-03-11 15:00:24 +08:00
|
|
|
Diag(Loc, getLangOpts().CPlusPlus0x ?
|
2011-10-15 13:09:34 +08:00
|
|
|
diag::warn_cxx98_compat_rvalue_reference :
|
|
|
|
diag::ext_rvalue_reference);
|
2009-03-23 08:00:23 +08:00
|
|
|
|
2012-04-10 09:32:12 +08:00
|
|
|
// GNU-style and C++11 attributes are allowed here, as is restrict.
|
|
|
|
ParseTypeQualifierListOpt(DS);
|
|
|
|
D.ExtendWithDeclSpec(DS);
|
|
|
|
|
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.
|
|
|
|
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
|
|
|
Kind == tok::amp),
|
2011-03-24 19:26:52 +08:00
|
|
|
DS.getAttributes(),
|
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
|
|
|
|
2012-03-29 09:16:42 +08:00
|
|
|
static void diagnoseMisplacedEllipsis(Parser &P, Declarator &D,
|
|
|
|
SourceLocation EllipsisLoc) {
|
|
|
|
if (EllipsisLoc.isValid()) {
|
|
|
|
FixItHint Insertion;
|
|
|
|
if (!D.getEllipsisLoc().isValid()) {
|
|
|
|
Insertion = FixItHint::CreateInsertion(D.getIdentifierLoc(), "...");
|
|
|
|
D.setEllipsisLoc(EllipsisLoc);
|
|
|
|
}
|
|
|
|
P.Diag(EllipsisLoc, diag::err_misplaced_ellipsis_in_declaration)
|
|
|
|
<< FixItHint::CreateRemoval(EllipsisLoc) << Insertion << !D.hasName();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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] '*' ']'
|
2012-04-10 09:32:12 +08:00
|
|
|
/// [C++11] direct-declarator '[' constant-expression[opt] ']'
|
|
|
|
/// attribute-specifier-seq[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]
|
2012-04-10 09:32:12 +08:00
|
|
|
/// [C++11] direct-declarator '(' parameter-declaration-clause ')'
|
|
|
|
/// attribute-specifier-seq[opt] cv-qualifier-seq[opt]
|
|
|
|
/// ref-qualifier[opt] exception-specification[opt]
|
2008-10-31 17:07:45 +08:00
|
|
|
/// [C++] declarator-id
|
2012-04-10 09:32:12 +08:00
|
|
|
/// [C++11] declarator-id attribute-specifier-seq[opt]
|
2008-11-06 04:51:48 +08:00
|
|
|
///
|
|
|
|
/// declarator-id: [C++ 8]
|
2010-12-24 06:44:42 +08:00
|
|
|
/// '...'[opt] id-expression
|
2008-11-06 04:51:48 +08:00
|
|
|
/// '::'[opt] nested-name-specifier[opt] type-name
|
|
|
|
///
|
|
|
|
/// id-expression: [C++ 5.1]
|
|
|
|
/// unqualified-id
|
2009-09-26 05:45:23 +08:00
|
|
|
/// qualified-id
|
2008-11-06 04:51:48 +08:00
|
|
|
///
|
|
|
|
/// unqualified-id: [C++ 5.1]
|
2009-09-09 23:08:12 +08:00
|
|
|
/// identifier
|
2008-11-09 00:45:02 +08:00
|
|
|
/// operator-function-id
|
2009-09-26 05:45:23 +08:00
|
|
|
/// conversion-function-id
|
2009-09-09 23:08:12 +08:00
|
|
|
/// '~' 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
|
|
|
///
|
2012-03-27 09:42:32 +08:00
|
|
|
/// Note, any additional constructs added here may need corresponding changes
|
|
|
|
/// in isConstructorDeclarator.
|
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());
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) {
|
2009-11-03 09:35:08 +08:00
|
|
|
// ParseDeclaratorInternal might already have parsed the scope.
|
2010-04-09 00:38:48 +08:00
|
|
|
if (D.getCXXScopeSpec().isEmpty()) {
|
2011-11-08 01:33:42 +08:00
|
|
|
bool EnteringContext = D.getContext() == Declarator::FileContext ||
|
|
|
|
D.getContext() == Declarator::MemberContext;
|
|
|
|
ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(),
|
|
|
|
EnteringContext);
|
2010-02-26 16:45:28 +08:00
|
|
|
}
|
|
|
|
|
2010-04-09 00:38:48 +08:00
|
|
|
if (D.getCXXScopeSpec().isValid()) {
|
2010-07-03 01:43:08 +08:00
|
|
|
if (Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec()))
|
2009-12-12 04:04:54 +08:00
|
|
|
// Change the declaration context for name lookup, until this function
|
|
|
|
// is exited (and the declarator has been parsed).
|
|
|
|
DeclScopeObj.EnterDeclaratorScope();
|
2010-04-09 00:38:48 +08:00
|
|
|
}
|
|
|
|
|
2010-12-24 06:44:42 +08:00
|
|
|
// C++0x [dcl.fct]p14:
|
|
|
|
// There is a syntactic ambiguity when an ellipsis occurs at the end
|
|
|
|
// of a parameter-declaration-clause without a preceding comma. In
|
|
|
|
// this case, the ellipsis is parsed as part of the
|
|
|
|
// abstract-declarator if the type of the parameter names a template
|
|
|
|
// parameter pack that has not been expanded; otherwise, it is parsed
|
|
|
|
// as part of the parameter-declaration-clause.
|
2012-03-29 09:16:42 +08:00
|
|
|
if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() &&
|
2010-12-24 06:44:42 +08:00
|
|
|
!((D.getContext() == Declarator::PrototypeContext ||
|
|
|
|
D.getContext() == Declarator::BlockLiteralContext) &&
|
|
|
|
NextToken().is(tok::r_paren) &&
|
2012-03-29 09:16:42 +08:00
|
|
|
!Actions.containsUnexpandedParameterPacks(D))) {
|
|
|
|
SourceLocation EllipsisLoc = ConsumeToken();
|
|
|
|
if (isPtrOperatorToken(Tok.getKind(), getLangOpts())) {
|
|
|
|
// The ellipsis was put in the wrong place. Recover, and explain to
|
|
|
|
// the user what they should have done.
|
|
|
|
ParseDeclarator(D);
|
|
|
|
diagnoseMisplacedEllipsis(*this, D, EllipsisLoc);
|
|
|
|
return;
|
|
|
|
} else
|
|
|
|
D.setEllipsisLoc(EllipsisLoc);
|
|
|
|
|
|
|
|
// The ellipsis can't be followed by a parenthesized declarator. We
|
|
|
|
// check for that in ParseParenDeclarator, after we have disambiguated
|
|
|
|
// the l_paren token.
|
|
|
|
}
|
|
|
|
|
2009-11-03 09:35:08 +08:00
|
|
|
if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) ||
|
|
|
|
Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) {
|
|
|
|
// We found something that indicates the start of an unqualified-id.
|
|
|
|
// Parse that unqualified-id.
|
2010-04-13 14:39:49 +08:00
|
|
|
bool AllowConstructorName;
|
|
|
|
if (D.getDeclSpec().hasTypeSpecifier())
|
|
|
|
AllowConstructorName = false;
|
|
|
|
else if (D.getCXXScopeSpec().isSet())
|
|
|
|
AllowConstructorName =
|
|
|
|
(D.getContext() == Declarator::FileContext ||
|
|
|
|
(D.getContext() == Declarator::MemberContext &&
|
|
|
|
D.getDeclSpec().isFriendSpecified()));
|
|
|
|
else
|
|
|
|
AllowConstructorName = (D.getContext() == Declarator::MemberContext);
|
|
|
|
|
2012-01-27 17:46:47 +08:00
|
|
|
SourceLocation TemplateKWLoc;
|
2009-11-03 09:35:08 +08:00
|
|
|
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
|
|
|
|
/*EnteringContext=*/true,
|
|
|
|
/*AllowDestructorName=*/true,
|
2010-01-14 01:31:36 +08:00
|
|
|
AllowConstructorName,
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType(),
|
2012-01-27 17:46:47 +08:00
|
|
|
TemplateKWLoc,
|
2010-04-09 00:38:48 +08:00
|
|
|
D.getName()) ||
|
|
|
|
// Once we're past the identifier, if the scope was bad, mark the
|
|
|
|
// whole declarator bad.
|
|
|
|
D.getCXXScopeSpec().isInvalid()) {
|
2008-11-27 06:40:03 +08:00
|
|
|
D.SetIdentifier(0, Tok.getLocation());
|
|
|
|
D.setInvalidType(true);
|
2009-11-03 09:35:08 +08:00
|
|
|
} else {
|
|
|
|
// Parsed the unqualified-id; update range information and move along.
|
|
|
|
if (D.getSourceRange().getBegin().isInvalid())
|
|
|
|
D.SetRangeBegin(D.getName().getSourceRange().getBegin());
|
|
|
|
D.SetRangeEnd(D.getName().getSourceRange().getEnd());
|
2008-11-27 06:40:03 +08:00
|
|
|
}
|
2009-11-03 09:35:08 +08:00
|
|
|
goto PastIdentifier;
|
2008-11-08 06:02:30 +08:00
|
|
|
}
|
2009-11-03 09:35:08 +08:00
|
|
|
} else if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) {
|
2012-03-11 15:00:24 +08:00
|
|
|
assert(!getLangOpts().CPlusPlus &&
|
2008-11-27 06:40:03 +08:00
|
|
|
"There's a C++-specific check for tok::identifier above");
|
|
|
|
assert(Tok.getIdentifierInfo() && "Not an identifier?");
|
|
|
|
D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
|
|
|
|
ConsumeToken();
|
2009-11-03 09:35:08 +08:00
|
|
|
goto PastIdentifier;
|
|
|
|
}
|
2012-03-29 09:16:42 +08:00
|
|
|
|
2009-11-03 09:35:08 +08:00
|
|
|
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);
|
2010-01-14 01:31:36 +08:00
|
|
|
|
|
|
|
// If the declarator was parenthesized, we entered the declarator
|
|
|
|
// scope when parsing the parenthesized declarator, then exited
|
|
|
|
// the scope already. Re-enter the scope, if we need to.
|
|
|
|
if (D.getCXXScopeSpec().isSet()) {
|
2010-08-18 07:50:37 +08:00
|
|
|
// If there was an error parsing parenthesized declarator, declarator
|
2012-03-29 09:16:42 +08:00
|
|
|
// scope may have been entered before. Don't do it again.
|
2010-08-18 07:50:37 +08:00
|
|
|
if (!D.isInvalidType() &&
|
|
|
|
Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec()))
|
2010-01-14 01:31:36 +08:00
|
|
|
// Change the declaration context for name lookup, until this function
|
|
|
|
// is exited (and the declarator has been parsed).
|
2010-08-18 07:50:37 +08:00
|
|
|
DeclScopeObj.EnterDeclaratorScope();
|
2010-01-14 01:31:36 +08:00
|
|
|
}
|
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();
|
2012-03-11 15:00:24 +08:00
|
|
|
else if (getLangOpts().CPlusPlus)
|
|
|
|
Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus;
|
2008-11-09 00:45:02 +08:00
|
|
|
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
|
|
|
}
|
2009-09-09 23:08:12 +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?");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-04-10 09:32:12 +08:00
|
|
|
// Don't parse attributes unless we have parsed an unparenthesized name.
|
|
|
|
if (D.hasName() && !D.getNumTypeObjects())
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseCXX0XAttributes(D);
|
2009-11-21 16:43:09 +08:00
|
|
|
|
2006-08-07 01:24:14 +08:00
|
|
|
while (1) {
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
2011-12-04 13:04:18 +08:00
|
|
|
// Enter function-declaration scope, limiting any declarators to the
|
|
|
|
// function prototype scope, including parameter declarators.
|
|
|
|
ParseScope PrototypeScope(this,
|
|
|
|
Scope::FunctionPrototypeScope|Scope::DeclScope);
|
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.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) {
|
2008-10-20 10:05:46 +08:00
|
|
|
// 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;
|
|
|
|
}
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
|
|
|
ParseFunctionDeclarator(D, attrs, T);
|
2011-12-04 13:04:18 +08:00
|
|
|
PrototypeScope.Exit();
|
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;
|
|
|
|
}
|
|
|
|
}
|
2011-12-04 13:04:18 +08:00
|
|
|
}
|
2006-08-07 01:24:14 +08:00
|
|
|
|
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
|
2009-09-09 23:08:12 +08:00
|
|
|
/// parens for precedence. If we find that these are actually function
|
2008-04-06 13:45:57 +08:00
|
|
|
/// 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) {
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
|
|
|
|
2008-04-06 13:45:57 +08:00
|
|
|
assert(!D.isPastIdentifier() && "Should be called before passing identifier");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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.
|
|
|
|
//
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
2008-10-20 10:05:46 +08:00
|
|
|
bool RequiresArg = false;
|
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseGNUAttributes(attrs);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 10:05:46 +08:00
|
|
|
// 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) ||
|
2010-05-19 00:57:00 +08:00
|
|
|
Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___fastcall) ||
|
2011-08-18 17:59:55 +08:00
|
|
|
Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr64) ||
|
2011-08-25 08:36:46 +08:00
|
|
|
Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) {
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseMicrosoftTypeAttributes(attrs);
|
2009-06-09 07:27:34 +08:00
|
|
|
}
|
2010-09-03 09:29:35 +08:00
|
|
|
// Eat any Borland extensions.
|
2010-11-10 13:59:39 +08:00
|
|
|
if (Tok.is(tok::kw___pascal))
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseBorlandTypeAttributes(attrs);
|
2009-09-09 23:08:12 +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;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-06 13:45:57 +08:00
|
|
|
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.
|
2012-03-28 07:05:05 +08:00
|
|
|
(getLangOpts().CPlusPlus && Tok.is(tok::ellipsis) &&
|
|
|
|
NextToken().is(tok::r_paren)) || // C++ int(...)
|
2012-04-11 12:01:28 +08:00
|
|
|
isDeclarationSpecifier() || // 'int(int)' is a function.
|
|
|
|
isCXX11AttributeSpecifier()) { // 'int([[]]int)' is a function.
|
2008-04-06 13:45:57 +08:00
|
|
|
// 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;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-06 13:45:57 +08:00
|
|
|
// If this is a grouping paren, handle:
|
|
|
|
// direct-declarator: '(' declarator ')'
|
|
|
|
// direct-declarator: '(' attributes declarator ')'
|
|
|
|
if (isGrouping) {
|
2012-03-29 09:16:42 +08:00
|
|
|
SourceLocation EllipsisLoc = D.getEllipsisLoc();
|
|
|
|
D.setEllipsisLoc(SourceLocation());
|
|
|
|
|
2008-10-07 18:21:57 +08:00
|
|
|
bool hadGroupingParens = D.hasGroupingParens();
|
2008-10-07 01:10:33 +08:00
|
|
|
D.setGroupingParens(true);
|
2008-11-22 03:14:01 +08:00
|
|
|
ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
|
2008-04-06 13:45:57 +08:00
|
|
|
// Match the ')'.
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
|
|
|
D.AddTypeInfo(DeclaratorChunk::getParen(T.getOpenLocation(),
|
|
|
|
T.getCloseLocation()),
|
|
|
|
attrs, T.getCloseLocation());
|
2008-10-07 18:21:57 +08:00
|
|
|
|
|
|
|
D.setGroupingParens(hadGroupingParens);
|
2012-03-29 09:16:42 +08:00
|
|
|
|
|
|
|
// An ellipsis cannot be placed outside parentheses.
|
|
|
|
if (EllipsisLoc.isValid())
|
|
|
|
diagnoseMisplacedEllipsis(*this, D, EllipsisLoc);
|
|
|
|
|
2008-04-06 13:45:57 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-06 13:45:57 +08:00
|
|
|
// 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());
|
|
|
|
|
2011-12-04 13:04:18 +08:00
|
|
|
// Enter function-declaration scope, limiting any declarators to the
|
|
|
|
// function prototype scope, including parameter declarators.
|
|
|
|
ParseScope PrototypeScope(this,
|
|
|
|
Scope::FunctionPrototypeScope|Scope::DeclScope);
|
2011-10-13 00:37:45 +08:00
|
|
|
ParseFunctionDeclarator(D, attrs, T, RequiresArg);
|
2011-12-04 13:04:18 +08:00
|
|
|
PrototypeScope.Exit();
|
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
|
|
|
///
|
2012-04-10 09:32:12 +08:00
|
|
|
/// If FirstArgAttrs 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.
|
2008-10-20 10:05:46 +08:00
|
|
|
///
|
2012-04-10 09:32:12 +08:00
|
|
|
/// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt],
|
|
|
|
/// (C++11) ref-qualifier[opt], exception-specification[opt],
|
|
|
|
/// (C++11) attribute-specifier-seq[opt], and (C++11) trailing-return-type[opt].
|
2008-10-25 05:46:40 +08:00
|
|
|
///
|
2012-04-10 09:32:12 +08:00
|
|
|
/// [C++11] exception-specification:
|
2011-03-05 22:45:16 +08:00
|
|
|
/// dynamic-exception-specification
|
|
|
|
/// noexcept-specification
|
|
|
|
///
|
2011-10-13 00:37:45 +08:00
|
|
|
void Parser::ParseFunctionDeclarator(Declarator &D,
|
2012-04-10 09:32:12 +08:00
|
|
|
ParsedAttributes &FirstArgAttrs,
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker &Tracker,
|
2008-10-20 10:05:46 +08:00
|
|
|
bool RequiresArg) {
|
2011-12-04 13:04:18 +08:00
|
|
|
assert(getCurScope()->isFunctionPrototypeScope() &&
|
|
|
|
"Should call from a Function scope");
|
2008-04-06 13:45:57 +08:00
|
|
|
// lparen is already consumed!
|
|
|
|
assert(D.isPastIdentifier() && "Should not call before identifier!");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-06 00:44:18 +08:00
|
|
|
// This should be true when the function has typed arguments.
|
|
|
|
// Otherwise, it is treated as a K&R-style function.
|
|
|
|
bool HasProto = false;
|
|
|
|
// Build up an array of information about the parsed arguments.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
|
2011-07-06 00:44:18 +08:00
|
|
|
// Remember where we see an ellipsis, if any.
|
|
|
|
SourceLocation EllipsisLoc;
|
|
|
|
|
|
|
|
DeclSpec DS(AttrFactory);
|
|
|
|
bool RefQualifierIsLValueRef = true;
|
|
|
|
SourceLocation RefQualifierLoc;
|
2011-10-19 14:04:55 +08:00
|
|
|
SourceLocation ConstQualifierLoc;
|
|
|
|
SourceLocation VolatileQualifierLoc;
|
2011-07-06 00:44:18 +08:00
|
|
|
ExceptionSpecificationType ESpecType = EST_None;
|
|
|
|
SourceRange ESpecRange;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<ParsedType, 2> DynamicExceptions;
|
|
|
|
SmallVector<SourceRange, 2> DynamicExceptionRanges;
|
2011-07-06 00:44:18 +08:00
|
|
|
ExprResult NoexceptExpr;
|
2012-04-10 09:32:12 +08:00
|
|
|
ParsedAttributes FnAttrs(AttrFactory);
|
2012-06-12 09:51:59 +08:00
|
|
|
TypeResult TrailingReturnType;
|
2012-04-10 09:32:12 +08:00
|
|
|
|
2012-02-29 18:24:19 +08:00
|
|
|
Actions.ActOnStartFunctionDeclarator();
|
|
|
|
|
2011-07-06 00:44:18 +08:00
|
|
|
SourceLocation EndLoc;
|
|
|
|
if (isFunctionDeclaratorIdentifierList()) {
|
2010-11-10 13:59:39 +08:00
|
|
|
if (RequiresArg)
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_argument_required_after_attribute);
|
2008-10-25 05:46:40 +08:00
|
|
|
|
2011-07-06 00:44:18 +08:00
|
|
|
ParseFunctionDeclaratorIdentifierList(D, ParamInfo);
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
Tracker.consumeClose();
|
|
|
|
EndLoc = Tracker.getCloseLocation();
|
2011-07-06 00:44:18 +08:00
|
|
|
} else {
|
|
|
|
if (Tok.isNot(tok::r_paren))
|
2012-04-10 09:32:12 +08:00
|
|
|
ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc);
|
2011-07-06 00:44:18 +08:00
|
|
|
else if (RequiresArg)
|
|
|
|
Diag(Tok, diag::err_argument_required_after_attribute);
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
HasProto = ParamInfo.size() || getLangOpts().CPlusPlus;
|
2011-07-06 00:44:18 +08:00
|
|
|
|
|
|
|
// If we have the closing ')', eat it.
|
2011-10-13 00:37:45 +08:00
|
|
|
Tracker.consumeClose();
|
|
|
|
EndLoc = Tracker.getCloseLocation();
|
2008-10-25 05:46:40 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus) {
|
2012-04-10 09:32:12 +08:00
|
|
|
// FIXME: Accept these components in any order, and produce fixits to
|
|
|
|
// correct the order if the user gets it wrong. Ideally we should deal
|
|
|
|
// with the virt-specifier-seq and pure-specifier in the same way.
|
2010-12-24 10:08:15 +08:00
|
|
|
|
2011-07-06 00:44:18 +08:00
|
|
|
// Parse cv-qualifier-seq[opt].
|
2012-04-10 09:32:12 +08:00
|
|
|
ParseTypeQualifierListOpt(DS, false /*no attributes*/, false);
|
|
|
|
if (!DS.getSourceRange().getEnd().isInvalid()) {
|
|
|
|
EndLoc = DS.getSourceRange().getEnd();
|
|
|
|
ConstQualifierLoc = DS.getConstSpecLoc();
|
|
|
|
VolatileQualifierLoc = DS.getVolatileSpecLoc();
|
|
|
|
}
|
2008-11-25 11:22:00 +08:00
|
|
|
|
2011-07-06 00:44:18 +08:00
|
|
|
// Parse ref-qualifier[opt].
|
2011-01-26 11:43:54 +08:00
|
|
|
if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) {
|
2012-03-11 15:00:24 +08:00
|
|
|
Diag(Tok, getLangOpts().CPlusPlus0x ?
|
2011-10-15 13:09:34 +08:00
|
|
|
diag::warn_cxx98_compat_ref_qualifier :
|
|
|
|
diag::ext_ref_qualifier);
|
2012-04-10 09:32:12 +08:00
|
|
|
|
2011-01-26 11:43:54 +08:00
|
|
|
RefQualifierIsLValueRef = Tok.is(tok::amp);
|
|
|
|
RefQualifierLoc = ConsumeToken();
|
|
|
|
EndLoc = RefQualifierLoc;
|
|
|
|
}
|
2011-03-05 22:45:16 +08:00
|
|
|
|
2012-04-16 15:05:22 +08:00
|
|
|
// C++11 [expr.prim.general]p3:
|
|
|
|
// If a declaration declares a member function or member function
|
|
|
|
// template of a class X, the expression this is a prvalue of type
|
|
|
|
// "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
|
|
|
|
// and the end of the function-definition, member-declarator, or
|
|
|
|
// declarator.
|
|
|
|
bool IsCXX11MemberFunction =
|
|
|
|
getLangOpts().CPlusPlus0x &&
|
|
|
|
(D.getContext() == Declarator::MemberContext ||
|
|
|
|
(D.getContext() == Declarator::FileContext &&
|
|
|
|
D.getCXXScopeSpec().isValid() &&
|
|
|
|
Actions.CurContext->isRecord()));
|
|
|
|
Sema::CXXThisScopeRAII ThisScope(Actions,
|
|
|
|
dyn_cast<CXXRecordDecl>(Actions.CurContext),
|
|
|
|
DS.getTypeQualifiers(),
|
|
|
|
IsCXX11MemberFunction);
|
2012-05-03 06:22:32 +08:00
|
|
|
|
2008-11-25 11:22:00 +08:00
|
|
|
// Parse exception-specification[opt].
|
2012-05-03 06:22:32 +08:00
|
|
|
ESpecType = tryParseExceptionSpecification(ESpecRange,
|
2012-04-17 02:27:27 +08:00
|
|
|
DynamicExceptions,
|
|
|
|
DynamicExceptionRanges,
|
2012-05-03 06:22:32 +08:00
|
|
|
NoexceptExpr);
|
2011-03-05 22:45:16 +08:00
|
|
|
if (ESpecType != EST_None)
|
|
|
|
EndLoc = ESpecRange.getEnd();
|
2010-10-02 02:44:50 +08:00
|
|
|
|
2012-04-10 09:32:12 +08:00
|
|
|
// Parse attribute-specifier-seq[opt]. Per DR 979 and DR 1297, this goes
|
|
|
|
// after the exception-specification.
|
|
|
|
MaybeParseCXX0XAttributes(FnAttrs);
|
|
|
|
|
2011-07-06 00:44:18 +08:00
|
|
|
// Parse trailing-return-type[opt].
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) {
|
2011-10-15 13:09:34 +08:00
|
|
|
Diag(Tok, diag::warn_cxx98_compat_trailing_return_type);
|
2011-08-04 23:30:47 +08:00
|
|
|
SourceRange Range;
|
2012-06-12 09:51:59 +08:00
|
|
|
TrailingReturnType = ParseTrailingReturnType(Range);
|
2011-08-04 23:30:47 +08:00
|
|
|
if (Range.getEnd().isValid())
|
|
|
|
EndLoc = Range.getEnd();
|
2010-10-02 02:44:50 +08:00
|
|
|
}
|
2008-10-25 05:46:40 +08:00
|
|
|
}
|
2009-05-30 02:02:33 +08:00
|
|
|
}
|
|
|
|
|
2011-07-06 00:44:18 +08:00
|
|
|
// Remember that we parsed a function type, and remember the attributes.
|
|
|
|
D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto,
|
|
|
|
/*isVariadic=*/EllipsisLoc.isValid(),
|
|
|
|
EllipsisLoc,
|
|
|
|
ParamInfo.data(), ParamInfo.size(),
|
|
|
|
DS.getTypeQualifiers(),
|
|
|
|
RefQualifierIsLValueRef,
|
2011-10-19 14:04:55 +08:00
|
|
|
RefQualifierLoc, ConstQualifierLoc,
|
|
|
|
VolatileQualifierLoc,
|
2011-07-14 05:47:47 +08:00
|
|
|
/*MutableLoc=*/SourceLocation(),
|
2011-07-06 00:44:18 +08:00
|
|
|
ESpecType, ESpecRange.getBegin(),
|
|
|
|
DynamicExceptions.data(),
|
|
|
|
DynamicExceptionRanges.data(),
|
|
|
|
DynamicExceptions.size(),
|
|
|
|
NoexceptExpr.isUsable() ?
|
|
|
|
NoexceptExpr.get() : 0,
|
2011-10-13 00:37:45 +08:00
|
|
|
Tracker.getOpenLocation(),
|
|
|
|
EndLoc, D,
|
2011-07-06 00:44:18 +08:00
|
|
|
TrailingReturnType),
|
2012-04-10 09:32:12 +08:00
|
|
|
FnAttrs, EndLoc);
|
2012-02-29 18:24:19 +08:00
|
|
|
|
|
|
|
Actions.ActOnEndFunctionDeclarator();
|
2011-07-06 00:44:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// isFunctionDeclaratorIdentifierList - This parameter list may have an
|
|
|
|
/// identifier list form for a K&R-style function: void foo(a,b,c)
|
|
|
|
///
|
|
|
|
/// Note that identifier-lists are only allowed for normal declarators, not for
|
|
|
|
/// abstract-declarators.
|
|
|
|
bool Parser::isFunctionDeclaratorIdentifierList() {
|
2012-03-11 15:00:24 +08:00
|
|
|
return !getLangOpts().CPlusPlus
|
2011-07-06 00:44:18 +08:00
|
|
|
&& Tok.is(tok::identifier)
|
|
|
|
&& !TryAltiVecVectorToken()
|
|
|
|
// K&R identifier lists can't have typedefs as identifiers, per C99
|
|
|
|
// 6.7.5.3p11.
|
|
|
|
&& (TryAnnotateTypeOrScopeToken() || !Tok.is(tok::annot_typename))
|
|
|
|
// Identifier lists follow a really simple grammar: the identifiers can
|
|
|
|
// be followed *only* by a ", identifier" or ")". However, K&R
|
|
|
|
// identifier lists are really rare in the brave new modern world, and
|
|
|
|
// it is very common for someone to typo a type in a non-K&R style
|
|
|
|
// list. If we are presented with something like: "void foo(intptr x,
|
|
|
|
// float y)", we don't want to start parsing the function declarator as
|
|
|
|
// though it is a K&R style declarator just because intptr is an
|
|
|
|
// invalid type.
|
|
|
|
//
|
|
|
|
// To handle this, we check to see if the token after the first
|
|
|
|
// identifier is a "," or ")". Only then do we parse it as an
|
|
|
|
// identifier list.
|
|
|
|
&& (NextToken().is(tok::comma) || NextToken().is(tok::r_paren));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator
|
|
|
|
/// we found a K&R-style identifier list instead of a typed parameter list.
|
|
|
|
///
|
|
|
|
/// After returning, ParamInfo will hold the parsed parameters.
|
|
|
|
///
|
|
|
|
/// identifier-list: [C99 6.7.5]
|
|
|
|
/// identifier
|
|
|
|
/// identifier-list ',' identifier
|
|
|
|
///
|
|
|
|
void Parser::ParseFunctionDeclaratorIdentifierList(
|
|
|
|
Declarator &D,
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo) {
|
2011-07-06 00:44:18 +08:00
|
|
|
// 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);
|
|
|
|
|
|
|
|
// Maintain an efficient lookup of params we have seen so far.
|
|
|
|
llvm::SmallSet<const IdentifierInfo*, 16> ParamsSoFar;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
// If this isn't an identifier, report the error and skip until ')'.
|
|
|
|
if (Tok.isNot(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true);
|
|
|
|
// Forget we parsed anything.
|
|
|
|
ParamInfo.clear();
|
|
|
|
return;
|
2008-10-20 10:05:46 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-06 00:44:18 +08:00
|
|
|
IdentifierInfo *ParmII = Tok.getIdentifierInfo();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-06 00:44:18 +08:00
|
|
|
// Reject 'typedef int y; int test(x, y)', but continue parsing.
|
|
|
|
if (Actions.getTypeName(*ParmII, Tok.getLocation(), getCurScope()))
|
|
|
|
Diag(Tok, diag::err_unexpected_typedef_ident) << ParmII;
|
2008-04-08 12:40:51 +08:00
|
|
|
|
2011-07-06 00:44:18 +08:00
|
|
|
// Verify that the argument identifier has not already been mentioned.
|
|
|
|
if (!ParamsSoFar.insert(ParmII)) {
|
|
|
|
Diag(Tok, diag::err_param_redefinition) << ParmII;
|
|
|
|
} else {
|
|
|
|
// Remember this identifier in ParamInfo.
|
|
|
|
ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
|
|
|
|
Tok.getLocation(),
|
|
|
|
0));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Eat the identifier.
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// The list continues if we see a comma.
|
|
|
|
if (Tok.isNot(tok::comma))
|
|
|
|
break;
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseParameterDeclarationClause - Parse a (possibly empty) parameter-list
|
|
|
|
/// after the opening parenthesis. This function will not parse a K&R-style
|
|
|
|
/// identifier list.
|
|
|
|
///
|
2012-04-11 12:01:28 +08:00
|
|
|
/// D is the declarator being parsed. If FirstArgAttrs is non-null, then the
|
|
|
|
/// caller parsed those arguments immediately after the open paren - they should
|
|
|
|
/// be considered to be part of the first parameter.
|
2011-07-06 00:44:18 +08:00
|
|
|
///
|
|
|
|
/// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will
|
|
|
|
/// be the location of the ellipsis, if any was parsed.
|
|
|
|
///
|
|
|
|
/// parameter-type-list: [C99 6.7.5]
|
|
|
|
/// parameter-list
|
|
|
|
/// parameter-list ',' '...'
|
|
|
|
/// [C++] parameter-list '...'
|
|
|
|
///
|
|
|
|
/// parameter-list: [C99 6.7.5]
|
|
|
|
/// parameter-declaration
|
|
|
|
/// parameter-list ',' parameter-declaration
|
|
|
|
///
|
|
|
|
/// parameter-declaration: [C99 6.7.5]
|
|
|
|
/// declaration-specifiers declarator
|
|
|
|
/// [C++] declaration-specifiers declarator '=' assignment-expression
|
2012-03-14 23:54:00 +08:00
|
|
|
/// [C++11] initializer-clause
|
2011-07-06 00:44:18 +08:00
|
|
|
/// [GNU] declaration-specifiers declarator attributes
|
|
|
|
/// declaration-specifiers abstract-declarator[opt]
|
|
|
|
/// [C++] declaration-specifiers abstract-declarator[opt]
|
|
|
|
/// '=' assignment-expression
|
|
|
|
/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
|
2012-04-11 12:01:28 +08:00
|
|
|
/// [C++11] attribute-specifier-seq parameter-declaration
|
2011-07-06 00:44:18 +08:00
|
|
|
///
|
|
|
|
void Parser::ParseParameterDeclarationClause(
|
|
|
|
Declarator &D,
|
2012-04-11 12:01:28 +08:00
|
|
|
ParsedAttributes &FirstArgAttrs,
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo,
|
2011-07-06 00:44:18 +08:00
|
|
|
SourceLocation &EllipsisLoc) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
while (1) {
|
|
|
|
if (Tok.is(tok::ellipsis)) {
|
2012-04-11 12:01:28 +08:00
|
|
|
// FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
|
|
|
|
// before deciding this was a parameter-declaration-clause.
|
2009-02-18 15:07:28 +08:00
|
|
|
EllipsisLoc = ConsumeToken(); // Consume the ellipsis.
|
2008-04-06 14:57:35 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-12-24 10:08:15 +08:00
|
|
|
|
|
|
|
// Parse the declaration-specifiers.
|
|
|
|
// Just use the ParsingDeclaration "scope" of the declarator.
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2011-10-13 00:37:45 +08:00
|
|
|
|
2012-04-11 12:01:28 +08:00
|
|
|
// Parse any C++11 attributes.
|
|
|
|
MaybeParseCXX0XAttributes(DS.getAttributes());
|
|
|
|
|
2010-10-11 20:59:39 +08:00
|
|
|
// Skip any Microsoft attributes before a param.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square))
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseMicrosoftAttributes(DS.getAttributes());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
SourceLocation DSStart = Tok.getLocation();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 10:05:46 +08:00
|
|
|
// If the caller parsed attributes for the first argument, add them now.
|
2010-12-24 10:08:15 +08:00
|
|
|
// Take them so that we only apply the attributes to the first parameter.
|
2011-07-06 00:44:18 +08:00
|
|
|
// FIXME: If we can leave the attributes in the token stream somehow, we can
|
2012-04-11 12:01:28 +08:00
|
|
|
// get rid of a parameter (FirstArgAttrs) and this statement. It might be
|
|
|
|
// too much hassle.
|
|
|
|
DS.takeAttributesFrom(FirstArgAttrs);
|
2010-12-24 10:08:15 +08:00
|
|
|
|
2009-02-28 02:38:20 +08:00
|
|
|
ParseDeclarationSpecifiers(DS);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
// Parse the declarator. This is "PrototypeContext", because we must
|
|
|
|
// accept either 'declarator' or 'abstract-declarator' here.
|
|
|
|
Declarator ParmDecl(DS, Declarator::PrototypeContext);
|
|
|
|
ParseDeclarator(ParmDecl);
|
2006-08-07 01:24:14 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
// Parse GNU attributes, if present.
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseGNUAttributes(ParmDecl);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
// Remember this parsed parameter in ParamInfo.
|
|
|
|
IdentifierInfo *ParmII = ParmDecl.getIdentifier();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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.
|
2009-09-09 23:08:12 +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.
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), 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: Can we use a smart pointer for Toks?
|
|
|
|
DefArgToks = new CachedTokens;
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks,
|
2010-04-24 05:20:12 +08:00
|
|
|
/*StopAtSemi=*/true,
|
|
|
|
/*ConsumeFinalToken=*/false)) {
|
2008-12-17 05:30:33 +08:00
|
|
|
delete DefArgToks;
|
|
|
|
DefArgToks = 0;
|
2008-12-24 08:01:03 +08:00
|
|
|
Actions.ActOnParamDefaultArgumentError(Param);
|
2010-08-06 17:47:24 +08:00
|
|
|
} else {
|
|
|
|
// Mark the end of the default argument so that we know when to
|
|
|
|
// stop when we parse it later on.
|
|
|
|
Token DefArgEnd;
|
|
|
|
DefArgEnd.startToken();
|
|
|
|
DefArgEnd.setKind(tok::cxx_defaultarg_end);
|
|
|
|
DefArgEnd.setLocation(Tok.getLocation());
|
|
|
|
DefArgToks->push_back(DefArgEnd);
|
2009-09-09 23:08:12 +08:00
|
|
|
Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc,
|
2009-06-13 00:51:40 +08:00
|
|
|
(*DefArgToks)[1].getLocation());
|
2010-08-06 17:47:24 +08:00
|
|
|
}
|
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();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-09-12 04:24:53 +08:00
|
|
|
// The argument isn't actually potentially evaluated unless it is
|
|
|
|
// used.
|
|
|
|
EnterExpressionEvaluationContext Eval(Actions,
|
2012-02-21 08:37:24 +08:00
|
|
|
Sema::PotentiallyEvaluatedIfUsed,
|
|
|
|
Param);
|
2010-09-12 04:24:53 +08:00
|
|
|
|
2012-03-14 23:54:00 +08:00
|
|
|
ExprResult DefArgResult;
|
2012-03-19 06:25:45 +08:00
|
|
|
if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
|
|
|
|
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
|
2012-03-14 23:54:00 +08:00
|
|
|
DefArgResult = ParseBraceInitializer();
|
2012-03-19 06:25:45 +08:00
|
|
|
} else
|
2012-03-14 23:54:00 +08:00
|
|
|
DefArgResult = ParseAssignmentExpression();
|
2008-12-17 05:30:33 +08:00
|
|
|
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,
|
2010-08-24 07:25:46 +08:00
|
|
|
DefArgResult.take());
|
2008-12-17 05:30:33 +08:00
|
|
|
}
|
2008-04-08 12:40:51 +08:00
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
|
|
|
|
ParmDecl.getIdentifierLoc(), Param,
|
2008-12-17 05:30:33 +08:00
|
|
|
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.
|
2009-09-23 05:41:40 +08:00
|
|
|
if (Tok.isNot(tok::comma)) {
|
|
|
|
if (Tok.is(tok::ellipsis)) {
|
|
|
|
EllipsisLoc = ConsumeToken(); // Consume the ellipsis.
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().CPlusPlus) {
|
2009-09-23 05:41:40 +08:00
|
|
|
// We have ellipsis without a preceding ',', which is ill-formed
|
|
|
|
// in C. Complain and provide the fix.
|
|
|
|
Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis)
|
2010-04-01 01:46:05 +08:00
|
|
|
<< FixItHint::CreateInsertion(EllipsisLoc, ", ");
|
2009-09-23 05:41:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-06 14:57:35 +08:00
|
|
|
// Consume the comma.
|
|
|
|
ConsumeToken();
|
2006-08-07 01:24:14 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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] '*' ']'
|
2012-04-10 09:32:12 +08:00
|
|
|
/// [C++11] direct-declarator '[' constant-expression[opt] ']'
|
|
|
|
/// attribute-specifier-seq[opt]
|
2006-08-07 02:30:15 +08:00
|
|
|
void Parser::ParseBracketDeclarator(Declarator &D) {
|
2012-04-10 09:32:12 +08:00
|
|
|
if (CheckProhibitedCXX11Attribute())
|
|
|
|
return;
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_square);
|
|
|
|
T.consumeOpen();
|
2009-09-09 23:08:12 +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) {
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseCXX0XAttributes(attrs);
|
2009-11-21 16:43:09 +08:00
|
|
|
|
2008-12-18 15:27:21 +08:00
|
|
|
// Remember that we parsed the empty array type.
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult NumElements;
|
2011-03-24 19:26:52 +08:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0,
|
2011-10-13 00:37:45 +08:00
|
|
|
T.getOpenLocation(),
|
|
|
|
T.getCloseLocation()),
|
|
|
|
attrs, T.getCloseLocation());
|
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.
|
2012-03-09 16:00:36 +08:00
|
|
|
ExprResult ExprRes(Actions.ActOnNumericConstant(Tok, getCurScope()));
|
2008-12-18 15:27:21 +08:00
|
|
|
ConsumeToken();
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseCXX0XAttributes(attrs);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-18 15:27:21 +08:00
|
|
|
// Remember that we parsed a array type, and remember its features.
|
2011-03-24 19:26:52 +08:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0,
|
2010-12-24 10:08:15 +08:00
|
|
|
ExprRes.release(),
|
2011-10-13 00:37:45 +08:00
|
|
|
T.getOpenLocation(),
|
|
|
|
T.getCloseLocation()),
|
|
|
|
attrs, T.getCloseLocation());
|
2008-12-18 15:27:21 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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.
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2008-12-18 15:02:59 +08:00
|
|
|
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-08-07 02:30:15 +08:00
|
|
|
// Handle "direct-declarator [ type-qual-list[opt] * ]".
|
|
|
|
bool isStar = false;
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult NumElements;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 07:52:42 +08:00
|
|
|
// Parse the constant-expression or assignment-expression now (depending
|
|
|
|
// on dialect).
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus) {
|
2009-06-20 07:52:42 +08:00
|
|
|
NumElements = ParseConstantExpression();
|
2012-01-21 09:01:51 +08:00
|
|
|
} else {
|
|
|
|
EnterExpressionEvaluationContext Unevaluated(Actions,
|
|
|
|
Sema::ConstantEvaluated);
|
2009-06-20 07:52:42 +08:00
|
|
|
NumElements = ParseAssignmentExpression();
|
2012-01-21 09:01:51 +08:00
|
|
|
}
|
2006-08-13 02:40:58 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2009-02-10 02:23:29 +08:00
|
|
|
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseCXX0XAttributes(attrs);
|
2009-11-21 16:43:09 +08:00
|
|
|
|
2008-12-18 15:27:21 +08:00
|
|
|
// Remember that we parsed a array type, and remember its features.
|
2011-03-24 19:26:52 +08:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
|
2006-12-02 14:43:02 +08:00
|
|
|
StaticLoc.isValid(), isStar,
|
2009-07-06 23:59:29 +08:00
|
|
|
NumElements.release(),
|
2011-10-13 00:37:45 +08:00
|
|
|
T.getOpenLocation(),
|
|
|
|
T.getCloseLocation()),
|
|
|
|
attrs, T.getCloseLocation());
|
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();
|
|
|
|
|
2010-01-14 04:03:27 +08:00
|
|
|
const bool hasParens = Tok.is(tok::l_paren);
|
|
|
|
|
2012-01-21 09:01:51 +08:00
|
|
|
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
|
|
|
|
|
2009-05-22 18:22:50 +08:00
|
|
|
bool isCastExpr;
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType CastTy;
|
2009-05-22 18:22:50 +08:00
|
|
|
SourceRange CastRange;
|
2011-03-12 03:24:49 +08:00
|
|
|
ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr,
|
|
|
|
CastTy, CastRange);
|
2010-01-14 04:03:27 +08:00
|
|
|
if (hasParens)
|
|
|
|
DS.setTypeofParensRange(CastRange);
|
2009-05-22 18:22:50 +08:00
|
|
|
|
|
|
|
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());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-22 18:22:50 +08:00
|
|
|
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
|
|
|
|
2012-01-21 09:01:51 +08:00
|
|
|
// We might need to transform the operand if it is potentially evaluated.
|
|
|
|
Operand = Actions.HandleExprEvaluationContextForTypeof(Operand.get());
|
|
|
|
if (Operand.isInvalid()) {
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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,
|
2010-08-24 13:47:05 +08:00
|
|
|
DiagID, Operand.get()))
|
2009-08-04 04:12:06 +08:00
|
|
|
Diag(StartLoc, DiagID) << PrevSpec;
|
2009-05-22 18:22:18 +08:00
|
|
|
}
|
2010-03-01 02:33:55 +08:00
|
|
|
|
2011-12-24 01:00:35 +08:00
|
|
|
/// [C11] atomic-specifier:
|
2011-10-07 07:00:33 +08:00
|
|
|
/// _Atomic ( type-name )
|
|
|
|
///
|
|
|
|
void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
|
|
|
|
assert(Tok.is(tok::kw__Atomic) && "Not an atomic specifier");
|
|
|
|
|
|
|
|
SourceLocation StartLoc = ConsumeToken();
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
if (T.expectAndConsume(diag::err_expected_lparen_after, "_Atomic")) {
|
2011-10-07 07:00:33 +08:00
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeResult Result = ParseTypeName();
|
|
|
|
if (Result.isInvalid()) {
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Match the ')'
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2011-10-07 07:00:33 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
if (T.getCloseLocation().isInvalid())
|
2011-10-07 07:00:33 +08:00
|
|
|
return;
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
DS.setTypeofParensRange(T.getRange());
|
|
|
|
DS.SetRangeEnd(T.getCloseLocation());
|
2011-10-07 07:00:33 +08:00
|
|
|
|
|
|
|
const char *PrevSpec = 0;
|
|
|
|
unsigned DiagID;
|
|
|
|
if (DS.SetTypeSpecType(DeclSpec::TST_atomic, StartLoc, PrevSpec,
|
|
|
|
DiagID, Result.release()))
|
|
|
|
Diag(StartLoc, DiagID) << PrevSpec;
|
|
|
|
}
|
|
|
|
|
2010-03-01 02:33:55 +08:00
|
|
|
|
|
|
|
/// TryAltiVecVectorTokenOutOfLine - Out of line body that should only be called
|
|
|
|
/// from TryAltiVecVectorToken.
|
|
|
|
bool Parser::TryAltiVecVectorTokenOutOfLine() {
|
|
|
|
Token Next = NextToken();
|
|
|
|
switch (Next.getKind()) {
|
|
|
|
default: return false;
|
|
|
|
case tok::kw_short:
|
|
|
|
case tok::kw_long:
|
|
|
|
case tok::kw_signed:
|
|
|
|
case tok::kw_unsigned:
|
|
|
|
case tok::kw_void:
|
|
|
|
case tok::kw_char:
|
|
|
|
case tok::kw_int:
|
|
|
|
case tok::kw_float:
|
|
|
|
case tok::kw_double:
|
|
|
|
case tok::kw_bool:
|
|
|
|
case tok::kw___pixel:
|
|
|
|
Tok.setKind(tok::kw___vector);
|
|
|
|
return true;
|
|
|
|
case tok::identifier:
|
|
|
|
if (Next.getIdentifierInfo() == Ident_pixel) {
|
|
|
|
Tok.setKind(tok::kw___vector);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
|
|
|
|
const char *&PrevSpec, unsigned &DiagID,
|
|
|
|
bool &isInvalid) {
|
|
|
|
if (Tok.getIdentifierInfo() == Ident_vector) {
|
|
|
|
Token Next = NextToken();
|
|
|
|
switch (Next.getKind()) {
|
|
|
|
case tok::kw_short:
|
|
|
|
case tok::kw_long:
|
|
|
|
case tok::kw_signed:
|
|
|
|
case tok::kw_unsigned:
|
|
|
|
case tok::kw_void:
|
|
|
|
case tok::kw_char:
|
|
|
|
case tok::kw_int:
|
|
|
|
case tok::kw_float:
|
|
|
|
case tok::kw_double:
|
|
|
|
case tok::kw_bool:
|
|
|
|
case tok::kw___pixel:
|
|
|
|
isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
|
|
|
|
return true;
|
|
|
|
case tok::identifier:
|
|
|
|
if (Next.getIdentifierInfo() == Ident_pixel) {
|
|
|
|
isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2010-06-16 23:28:57 +08:00
|
|
|
} else if ((Tok.getIdentifierInfo() == Ident_pixel) &&
|
2010-03-01 02:33:55 +08:00
|
|
|
DS.isTypeAltiVecVector()) {
|
|
|
|
isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|