summaryrefslogtreecommitdiffstats
path: root/lib/Parse
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Parse')
-rw-r--r--lib/Parse/AttributeList.cpp24
-rw-r--r--lib/Parse/MinimalAction.cpp2
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp3
-rw-r--r--lib/Parse/ParseDecl.cpp126
-rw-r--r--lib/Parse/ParseDeclCXX.cpp270
-rw-r--r--lib/Parse/ParseExpr.cpp29
-rw-r--r--lib/Parse/ParseExprCXX.cpp113
-rw-r--r--lib/Parse/ParseObjc.cpp8
-rw-r--r--lib/Parse/ParseStmt.cpp187
-rw-r--r--lib/Parse/ParseTemplate.cpp50
-rw-r--r--lib/Parse/ParseTentative.cpp88
-rw-r--r--lib/Parse/Parser.cpp27
12 files changed, 722 insertions, 205 deletions
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index dde4bc8..df48e3a 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -17,11 +17,13 @@
using namespace clang;
AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc,
+ IdentifierInfo *sName, SourceLocation sLoc,
IdentifierInfo *pName, SourceLocation pLoc,
ActionBase::ExprTy **ExprList, unsigned numArgs,
- AttributeList *n, bool declspec)
- : AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc),
- NumArgs(numArgs), Next(n), DeclspecAttribute(declspec) {
+ AttributeList *n, bool declspec, bool cxx0x)
+ : AttrName(aName), AttrLoc(aLoc), ScopeName(sName), ScopeLoc(sLoc),
+ ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n),
+ DeclspecAttribute(declspec), CXX0XAttribute(cxx0x) {
if (numArgs == 0)
Args = 0;
@@ -59,13 +61,16 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("mode", AT_mode)
.Case("used", AT_used)
.Case("alias", AT_alias)
+ .Case("align", AT_aligned)
+ .Case("final", AT_final)
.Case("cdecl", AT_cdecl)
.Case("const", AT_const)
- .Case("packed", AT_packed)
- .Case("malloc", AT_malloc)
+ .Case("blocks", AT_blocks)
.Case("format", AT_format)
+ .Case("hiding", AT_hiding)
+ .Case("malloc", AT_malloc)
+ .Case("packed", AT_packed)
.Case("unused", AT_unused)
- .Case("blocks", AT_blocks)
.Case("aligned", AT_aligned)
.Case("cleanup", AT_cleanup)
.Case("nodebug", AT_nodebug)
@@ -76,15 +81,17 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("section", AT_section)
.Case("stdcall", AT_stdcall)
.Case("annotate", AT_annotate)
- .Case("noreturn", AT_noreturn)
- .Case("noinline", AT_noinline)
.Case("fastcall", AT_fastcall)
.Case("iboutlet", AT_IBOutlet)
+ .Case("noreturn", AT_noreturn)
+ .Case("noinline", AT_noinline)
+ .Case("override", AT_override)
.Case("sentinel", AT_sentinel)
.Case("NSObject", AT_nsobject)
.Case("dllimport", AT_dllimport)
.Case("dllexport", AT_dllexport)
.Case("may_alias", IgnoredAttribute) // FIXME: TBAA
+ .Case("base_check", AT_base_check)
.Case("deprecated", AT_deprecated)
.Case("visibility", AT_visibility)
.Case("destructor", AT_destructor)
@@ -103,6 +110,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("transparent_union", AT_transparent_union)
.Case("analyzer_noreturn", AT_analyzer_noreturn)
.Case("warn_unused_result", AT_warn_unused_result)
+ .Case("carries_dependency", AT_carries_dependency)
.Case("ns_returns_retained", AT_ns_returns_retained)
.Case("cf_returns_retained", AT_cf_returns_retained)
.Case("reqd_work_group_size", AT_reqd_wg_size)
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index 7681eac..aa0b89b 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -144,7 +144,7 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
Action::TypeTy *
MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc,
Scope *S, const CXXScopeSpec *SS,
- bool isClassName) {
+ bool isClassName, TypeTy *ObjectType) {
if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>())
if (TI->isTypeName)
return TI;
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index c34653e..b9314d2 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -37,7 +37,8 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D,
FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, move(TemplateParams));
else // FIXME: pass template information through
FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D,
- move(TemplateParams), 0, 0);
+ move(TemplateParams), 0, 0,
+ /*IsDefinition*/true);
HandleMemberFunctionDefaultArgs(D, FnD);
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 2bfda30..b13dc73 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1,3 +1,4 @@
+
//===--- ParseDecl.cpp - Declaration Parsing ------------------------------===//
//
// The LLVM Compiler Infrastructure
@@ -45,7 +46,7 @@ Action::TypeResult Parser::ParseTypeName(SourceRange *Range) {
return Actions.ActOnTypeName(CurScope, DeclaratorInfo);
}
-/// ParseAttributes - Parse a non-empty attributes list.
+/// ParseGNUAttributes - Parse a non-empty attributes list.
///
/// [GNU] attributes:
/// attribute
@@ -81,8 +82,8 @@ Action::TypeResult Parser::ParseTypeName(SourceRange *Range) {
/// attributes are very simple in practice. Until we find a bug, I don't see
/// a pressing need to implement the 2 token lookahead.
-AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
- assert(Tok.is(tok::kw___attribute) && "Not an attribute list!");
+AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) {
+ assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!");
AttributeList *CurrAttr = 0;
@@ -121,7 +122,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
if (Tok.is(tok::r_paren)) {
// __attribute__(( mode(byte) ))
ConsumeParen(); // ignore the right paren loc for now
- CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
ParmName, ParmLoc, 0, 0, CurrAttr);
} else if (Tok.is(tok::comma)) {
ConsumeToken();
@@ -145,8 +146,10 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
}
if (ArgExprsOk && Tok.is(tok::r_paren)) {
ConsumeParen(); // ignore the right paren loc for now
- CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName,
- ParmLoc, ArgExprs.take(), ArgExprs.size(), CurrAttr);
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
+ AttrNameLoc, ParmName, ParmLoc,
+ ArgExprs.take(), ArgExprs.size(),
+ CurrAttr);
}
}
} else { // not an identifier
@@ -155,7 +158,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
// parse a possibly empty comma separated list of expressions
// __attribute__(( nonnull() ))
ConsumeParen(); // ignore the right paren loc for now
- CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
0, SourceLocation(), 0, 0, CurrAttr);
break;
case tok::kw_char:
@@ -175,7 +178,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
// If it's a builtin type name, eat it and expect a rparen
// __attribute__(( vec_type_hint(char) ))
ConsumeToken();
- CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
0, SourceLocation(), 0, 0, CurrAttr);
if (Tok.is(tok::r_paren))
ConsumeParen();
@@ -203,20 +206,21 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
if (ArgExprsOk && Tok.is(tok::r_paren)) {
ConsumeParen(); // ignore the right paren loc for now
CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
- SourceLocation(), ArgExprs.take(), ArgExprs.size(),
+ AttrNameLoc, 0, SourceLocation(), ArgExprs.take(),
+ ArgExprs.size(),
CurrAttr);
}
break;
}
}
} else {
- CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
0, SourceLocation(), 0, 0, CurrAttr);
}
}
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
SkipUntil(tok::r_paren, false);
- SourceLocation Loc = Tok.getLocation();;
+ SourceLocation Loc = Tok.getLocation();
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
SkipUntil(tok::r_paren, false);
}
@@ -254,15 +258,15 @@ AttributeList* Parser::ParseMicrosoftDeclSpec(AttributeList *CurrAttr) {
OwningExprResult ArgExpr(ParseAssignmentExpression());
if (!ArgExpr.isInvalid()) {
ExprTy* ExprList = ArgExpr.take();
- CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
SourceLocation(), &ExprList, 1,
CurrAttr, true);
}
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
SkipUntil(tok::r_paren, false);
} else {
- CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, SourceLocation(),
- 0, 0, CurrAttr, true);
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
+ 0, SourceLocation(), 0, 0, CurrAttr, true);
}
}
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
@@ -281,7 +285,7 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) {
if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64))
// FIXME: Support these properly!
continue;
- CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
SourceLocation(), 0, 0, CurrAttr, true);
}
return CurrAttr;
@@ -304,26 +308,36 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) {
/// others... [FIXME]
///
Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
- SourceLocation &DeclEnd) {
+ SourceLocation &DeclEnd,
+ CXX0XAttributeList Attr) {
DeclPtrTy SingleDecl;
switch (Tok.getKind()) {
case tok::kw_template:
case tok::kw_export:
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd);
break;
case tok::kw_namespace:
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
SingleDecl = ParseNamespace(Context, DeclEnd);
break;
case tok::kw_using:
- SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd);
+ SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd, Attr);
break;
case tok::kw_static_assert:
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
break;
default:
- return ParseSimpleDeclaration(Context, DeclEnd);
+ return ParseSimpleDeclaration(Context, DeclEnd, Attr.AttrList);
}
-
+
// This routine returns a DeclGroup, if the thing we parsed only contains a
// single decl, convert it now.
return Actions.ConvertDeclToDeclGroup(SingleDecl);
@@ -337,9 +351,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
/// If RequireSemi is false, this does not check for a ';' at the end of the
/// declaration.
Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
- SourceLocation &DeclEnd) {
+ SourceLocation &DeclEnd,
+ AttributeList *Attr) {
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
+ if (Attr)
+ DS.AddAttributes(Attr);
ParseDeclarationSpecifiers(DS);
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
@@ -422,7 +439,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// short x, __attribute__((common)) var; -> declarator
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
D.AddAttributes(AttrList, Loc);
}
@@ -491,7 +508,7 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D,
// If attributes are present, parse them.
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
D.AddAttributes(AttrList, Loc);
}
@@ -988,7 +1005,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// GNU attributes support.
case tok::kw___attribute:
- DS.AddAttributes(ParseAttributes());
+ DS.AddAttributes(ParseGNUAttributes());
continue;
// Microsoft declspec support.
@@ -1522,7 +1539,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) {
// Attributes are only allowed here on successive declarators.
if (!FirstDeclarator && Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
DeclaratorInfo.D.AddAttributes(AttrList, Loc);
}
@@ -1543,7 +1560,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) {
// If attributes exist after the declarator, parse them.
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
DeclaratorInfo.D.AddAttributes(AttrList, Loc);
}
@@ -1667,7 +1684,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
AttributeList *AttrList = 0;
// If attributes exist after struct contents, parse them.
if (Tok.is(tok::kw___attribute))
- AttrList = ParseAttributes();
+ AttrList = ParseGNUAttributes();
Actions.ActOnFields(CurScope,
RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(),
@@ -1702,7 +1719,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
AttributeList *Attr = 0;
// If attributes exist after tag, parse them.
if (Tok.is(tok::kw___attribute))
- Attr = ParseAttributes();
+ Attr = ParseGNUAttributes();
CXXScopeSpec SS;
if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) {
@@ -1833,7 +1850,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) {
AttributeList *Attr = 0;
// If attributes exist after the identifier list, parse them.
if (Tok.is(tok::kw___attribute))
- Attr = ParseAttributes();
+ Attr = ParseGNUAttributes(); // FIXME: where do they do?
Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl,
EnumConstantDecls.data(), EnumConstantDecls.size(),
@@ -2049,8 +2066,20 @@ bool Parser::isDeclarationSpecifier() {
/// [GNU] attributes [ only if AttributesAllowed=true ]
/// type-qualifier-list type-qualifier
/// [GNU] type-qualifier-list attributes [ only if AttributesAllowed=true ]
+/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq
+/// if CXX0XAttributesAllowed = true
///
-void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) {
+void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed,
+ bool CXX0XAttributesAllowed) {
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ SourceLocation Loc = Tok.getLocation();
+ CXX0XAttributeList Attr = ParseCXX0XAttributes();
+ if (CXX0XAttributesAllowed)
+ DS.AddAttributes(Attr.AttrList);
+ else
+ Diag(Loc, diag::err_attributes_not_allowed);
+ }
+
while (1) {
bool isInvalid = false;
const char *PrevSpec = 0;
@@ -2075,14 +2104,14 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) {
case tok::kw___cdecl:
case tok::kw___stdcall:
case tok::kw___fastcall:
- if (AttributesAllowed) {
+ if (GNUAttributesAllowed) {
DS.AddAttributes(ParseMicrosoftTypeAttributes());
continue;
}
goto DoneWithTypeQuals;
case tok::kw___attribute:
- if (AttributesAllowed) {
- DS.AddAttributes(ParseAttributes());
+ if (GNUAttributesAllowed) {
+ DS.AddAttributes(ParseGNUAttributes());
continue; // do *not* consume the next token!
}
// otherwise, FALL THROUGH!
@@ -2221,7 +2250,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
//
// [GNU] Retricted references are allowed.
// [GNU] Attributes on references are allowed.
- ParseTypeQualifierListOpt(DS);
+ // [C++0x] Attributes on references are not allowed.
+ ParseTypeQualifierListOpt(DS, true, false);
D.ExtendWithDeclSpec(DS);
if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
@@ -2362,6 +2392,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
assert(D.isPastIdentifier() &&
"Haven't past the location of the identifier yet?");
+ // Don't parse attributes unless we have an identifier.
+ if (D.getIdentifier() && getLang().CPlusPlus
+ && isCXX0XAttributeSpecifier(true)) {
+ SourceLocation AttrEndLoc;
+ CXX0XAttributeList Attr = ParseCXX0XAttributes();
+ D.AddAttributes(Attr.AttrList, AttrEndLoc);
+ }
+
while (1) {
if (Tok.is(tok::l_paren)) {
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
@@ -2413,7 +2451,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
AttributeList *AttrList = 0;
bool RequiresArg = false;
if (Tok.is(tok::kw___attribute)) {
- AttrList = ParseAttributes();
+ AttrList = ParseGNUAttributes();
// We require that the argument list (if this is a non-grouping paren) be
// present even if the attribute list was empty.
@@ -2618,7 +2656,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// Parse GNU attributes, if present.
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
ParmDecl.AddAttributes(AttrList, Loc);
}
@@ -2722,6 +2760,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
bool hasAnyExceptionSpec = false;
llvm::SmallVector<TypeTy*, 2> Exceptions;
llvm::SmallVector<SourceRange, 2> ExceptionRanges;
+
if (getLang().CPlusPlus) {
// Parse cv-qualifier-seq[opt].
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
@@ -2842,6 +2881,12 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
// This code does a fast path to handle some of the most obvious cases.
if (Tok.getKind() == tok::r_square) {
SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+ //FIXME: Use these
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier(true)) {
+ Attr = ParseCXX0XAttributes();
+ }
+
// Remember that we parsed the empty array type.
OwningExprResult NumElements(Actions);
D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0,
@@ -2855,6 +2900,11 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
ConsumeToken();
SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+ //FIXME: Use these
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ Attr = ParseCXX0XAttributes();
+ }
// If there was an error parsing the assignment-expression, recover.
if (ExprRes.isInvalid())
@@ -2922,6 +2972,12 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+ //FIXME: Use these
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ Attr = ParseCXX0XAttributes();
+ }
+
// Remember that we parsed a array type, and remember its features.
D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
StaticLoc.isValid(), isStar,
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 914bfc9..505a4d8 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -69,7 +69,7 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
attrTok = Tok;
// FIXME: save these somewhere.
- AttrList = ParseAttributes();
+ AttrList = ParseGNUAttributes();
}
if (Tok.is(tok::equal)) {
@@ -97,8 +97,12 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
PP.getSourceManager(),
"parsing namespace");
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof))
- ParseExternalDeclaration();
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ Attr = ParseCXX0XAttributes();
+ ParseExternalDeclaration(Attr);
+ }
// Leave the namespace scope.
NamespaceScope.Exit();
@@ -175,15 +179,27 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) {
Tok.is(tok::l_brace)? Tok.getLocation()
: SourceLocation());
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ Attr = ParseCXX0XAttributes();
+ }
+
if (Tok.isNot(tok::l_brace)) {
- ParseDeclarationOrFunctionDefinition();
+ ParseDeclarationOrFunctionDefinition(Attr.AttrList);
return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec,
SourceLocation());
}
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
+
SourceLocation LBrace = ConsumeBrace();
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
- ParseExternalDeclaration();
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ Attr = ParseCXX0XAttributes();
+ ParseExternalDeclaration(Attr);
}
SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace);
@@ -193,7 +209,8 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) {
/// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
/// using-directive. Assumes that current token is 'using'.
Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
- SourceLocation &DeclEnd) {
+ SourceLocation &DeclEnd,
+ CXX0XAttributeList Attr) {
assert(Tok.is(tok::kw_using) && "Not using token");
// Eat 'using'.
@@ -206,9 +223,14 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
if (Tok.is(tok::kw_namespace))
// Next token after 'using' is 'namespace' so it must be using-directive
- return ParseUsingDirective(Context, UsingLoc, DeclEnd);
+ return ParseUsingDirective(Context, UsingLoc, DeclEnd, Attr.AttrList);
+
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
// Otherwise, it must be using-declaration.
+ // Ignore illegal attributes (the caller should already have issued an error.
return ParseUsingDeclaration(Context, UsingLoc, DeclEnd);
}
@@ -224,7 +246,8 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
///
Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
SourceLocation UsingLoc,
- SourceLocation &DeclEnd) {
+ SourceLocation &DeclEnd,
+ AttributeList *Attr) {
assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token");
// Eat 'namespace'.
@@ -239,7 +262,6 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
// Parse (optional) nested-name-specifier.
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
- AttributeList *AttrList = 0;
IdentifierInfo *NamespcName = 0;
SourceLocation IdentLoc = SourceLocation();
@@ -257,17 +279,20 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
IdentLoc = ConsumeToken();
// Parse (optional) attributes (most likely GNU strong-using extension).
- if (Tok.is(tok::kw___attribute))
- AttrList = ParseAttributes();
+ bool GNUAttr = false;
+ if (Tok.is(tok::kw___attribute)) {
+ GNUAttr = true;
+ Attr = addAttributeLists(Attr, ParseGNUAttributes());
+ }
// Eat ';'.
DeclEnd = Tok.getLocation();
ExpectAndConsume(tok::semi,
- AttrList ? diag::err_expected_semi_after_attribute_list :
+ GNUAttr ? diag::err_expected_semi_after_attribute_list :
diag::err_expected_semi_after_namespace_name, "", tok::semi);
return Actions.ActOnUsingDirective(CurScope, UsingLoc, NamespcLoc, SS,
- IdentLoc, NamespcName, AttrList);
+ IdentLoc, NamespcName, Attr);
}
/// ParseUsingDeclaration - Parse C++ using-declaration. Assumes that
@@ -323,7 +348,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
// Parse (optional) attributes (most likely GNU strong-using extension).
if (Tok.is(tok::kw___attribute))
- AttrList = ParseAttributes();
+ AttrList = ParseGNUAttributes();
// Eat ';'.
DeclEnd = Tok.getLocation();
@@ -538,14 +563,20 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
ConsumeToken();
}
- AttributeList *Attr = 0;
+ AttributeList *AttrList = 0;
// If attributes exist after tag, parse them.
if (Tok.is(tok::kw___attribute))
- Attr = ParseAttributes();
+ AttrList = ParseGNUAttributes();
// If declspecs exist after tag, parse them.
if (Tok.is(tok::kw___declspec))
- Attr = ParseMicrosoftDeclSpec(Attr);
+ AttrList = ParseMicrosoftDeclSpec(AttrList);
+
+ // If C++0x attributes exist here, parse them.
+ // FIXME: Are we consistent with the ordering of parsing of different
+ // styles of attributes?
+ if (isCXX0XAttributeSpecifier())
+ AttrList = addAttributeLists(AttrList, ParseCXX0XAttributes().AttrList);
if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_pod)) {
// GNU libstdc++ 4.2 uses __is_pod as the name of a struct template, but
@@ -683,7 +714,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Diag(StartLoc, diag::err_anon_type_definition)
<< DeclSpec::getSpecifierName(TagType);
- // Skip the rest of this declarator, up until the comma or semicolon.
SkipUntil(tok::comma, true);
if (TemplateId)
@@ -720,7 +750,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->RAngleLoc,
- Attr);
+ AttrList);
} else if (TUK == Action::TUK_Reference) {
TypeResult
= Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
@@ -775,7 +805,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->RAngleLoc,
- Attr,
+ AttrList,
Action::MultiTemplateParamsArg(Actions,
TemplateParams? &(*TemplateParams)[0] : 0,
TemplateParams? TemplateParams->size() : 0));
@@ -793,7 +823,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateInfo.ExternLoc,
TemplateInfo.TemplateLoc,
TagType, StartLoc, SS, Name,
- NameLoc, Attr);
+ NameLoc, AttrList);
} else {
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
TUK == Action::TUK_Definition) {
@@ -804,7 +834,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Declaration or definition of a class type
TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TUK, StartLoc, SS,
- Name, NameLoc, Attr, AS,
+ Name, NameLoc, AttrList, AS,
Action::MultiTemplateParamsArg(Actions,
TemplateParams? &(*TemplateParams)[0] : 0,
TemplateParams? TemplateParams->size() : 0),
@@ -1055,8 +1085,18 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return ParseCXXClassMemberDeclaration(AS, TemplateInfo);
}
+ CXX0XAttributeList AttrList;
+ // Optional C++0x attribute-specifier
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ AttrList = ParseCXX0XAttributes();
+ }
+
if (Tok.is(tok::kw_using)) {
// FIXME: Check for template aliases
+
+ if (AttrList.HasAttr)
+ Diag(AttrList.Range.getBegin(), diag::err_attributes_not_allowed)
+ << AttrList.Range;
// Eat 'using'.
SourceLocation UsingLoc = ConsumeToken();
@@ -1077,6 +1117,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// decl-specifier-seq:
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
+ DS.AddAttributes(AttrList.AttrList);
ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class);
Action::MultiTemplateParamsArg TemplateParams(Actions,
@@ -1103,6 +1144,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
}
+ // If attributes exist after the declarator, but before an '{', parse them.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
+ DeclaratorInfo.AddAttributes(AttrList, Loc);
+ }
+
// function-definition:
if (Tok.is(tok::l_brace)
|| (DeclaratorInfo.isFunctionDeclarator() &&
@@ -1139,7 +1187,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
bool Deleted = false;
while (1) {
-
// member-declarator:
// declarator pure-specifier[opt]
// declarator constant-initializer[opt]
@@ -1177,7 +1224,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// If attributes exist after the declarator, parse them.
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
DeclaratorInfo.AddAttributes(AttrList, Loc);
}
@@ -1197,6 +1244,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
move(TemplateParams),
BitfieldSize.release(),
Init.release(),
+ /*IsDefinition*/Deleted,
Deleted);
}
if (ThisDecl)
@@ -1227,7 +1275,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// Attributes are only allowed on the second declarator.
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
DeclaratorInfo.AddAttributes(AttrList, Loc);
}
@@ -1326,7 +1374,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
AttributeList *AttrList = 0;
// If attributes exist after class contents, parse them.
if (Tok.is(tok::kw___attribute))
- AttrList = ParseAttributes(); // FIXME: where should I put them?
+ AttrList = ParseGNUAttributes(); // FIXME: where should I put them?
Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl,
LBraceLoc, RBraceLoc);
@@ -1573,3 +1621,173 @@ void Parser::PopParsingClass() {
ClassStack.top()->NestedClasses.push_back(Victim);
Victim->TemplateScope = CurScope->getParent()->isTemplateParamScope();
}
+
+/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier. Currently only
+/// parses standard attributes.
+///
+/// [C++0x] attribute-specifier:
+/// '[' '[' attribute-list ']' ']'
+///
+/// [C++0x] attribute-list:
+/// attribute[opt]
+/// attribute-list ',' attribute[opt]
+///
+/// [C++0x] attribute:
+/// attribute-token attribute-argument-clause[opt]
+///
+/// [C++0x] attribute-token:
+/// identifier
+/// attribute-scoped-token
+///
+/// [C++0x] attribute-scoped-token:
+/// attribute-namespace '::' identifier
+///
+/// [C++0x] attribute-namespace:
+/// identifier
+///
+/// [C++0x] attribute-argument-clause:
+/// '(' balanced-token-seq ')'
+///
+/// [C++0x] balanced-token-seq:
+/// balanced-token
+/// balanced-token-seq balanced-token
+///
+/// [C++0x] balanced-token:
+/// '(' balanced-token-seq ')'
+/// '[' balanced-token-seq ']'
+/// '{' balanced-token-seq '}'
+/// any token but '(', ')', '[', ']', '{', or '}'
+CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) {
+ assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
+ && "Not a C++0x attribute list");
+
+ SourceLocation StartLoc = Tok.getLocation(), Loc;
+ AttributeList *CurrAttr = 0;
+
+ ConsumeBracket();
+ ConsumeBracket();
+
+ if (Tok.is(tok::comma)) {
+ Diag(Tok.getLocation(), diag::err_expected_ident);
+ ConsumeToken();
+ }
+
+ while (Tok.is(tok::identifier) || Tok.is(tok::comma)) {
+ // attribute not present
+ if (Tok.is(tok::comma)) {
+ ConsumeToken();
+ continue;
+ }
+
+ IdentifierInfo *ScopeName = 0, *AttrName = Tok.getIdentifierInfo();
+ SourceLocation ScopeLoc, AttrLoc = ConsumeToken();
+
+ // scoped attribute
+ if (Tok.is(tok::coloncolon)) {
+ ConsumeToken();
+
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected_ident);
+ SkipUntil(tok::r_square, tok::comma, true, true);
+ continue;
+ }
+
+ ScopeName = AttrName;
+ ScopeLoc = AttrLoc;
+
+ AttrName = Tok.getIdentifierInfo();
+ AttrLoc = ConsumeToken();
+ }
+
+ bool AttrParsed = false;
+ // No scoped names are supported; ideally we could put all non-standard
+ // attributes into namespaces.
+ if (!ScopeName) {
+ switch(AttributeList::getKind(AttrName))
+ {
+ // No arguments
+ case AttributeList::AT_base_check:
+ case AttributeList::AT_carries_dependency:
+ case AttributeList::AT_final:
+ case AttributeList::AT_hiding:
+ case AttributeList::AT_noreturn:
+ case AttributeList::AT_override: {
+ if (Tok.is(tok::l_paren)) {
+ Diag(Tok.getLocation(), diag::err_cxx0x_attribute_forbids_arguments)
+ << AttrName->getName();
+ break;
+ }
+
+ CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc, 0,
+ SourceLocation(), 0, 0, CurrAttr, false,
+ true);
+ AttrParsed = true;
+ break;
+ }
+
+ // One argument; must be a type-id or assignment-expression
+ case AttributeList::AT_aligned: {
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok.getLocation(), diag::err_cxx0x_attribute_requires_arguments)
+ << AttrName->getName();
+ break;
+ }
+ SourceLocation ParamLoc = ConsumeParen();
+
+ OwningExprResult ArgExpr = ParseCXX0XAlignArgument(ParamLoc);
+
+ MatchRHSPunctuation(tok::r_paren, ParamLoc);
+
+ ExprVector ArgExprs(Actions);
+ ArgExprs.push_back(ArgExpr.release());
+ CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc,
+ 0, ParamLoc, ArgExprs.take(), 1, CurrAttr,
+ false, true);
+
+ AttrParsed = true;
+ break;
+ }
+
+ // Silence warnings
+ default: break;
+ }
+ }
+
+ // Skip the entire parameter clause, if any
+ if (!AttrParsed && Tok.is(tok::l_paren)) {
+ ConsumeParen();
+ // SkipUntil maintains the balancedness of tokens.
+ SkipUntil(tok::r_paren, false);
+ }
+ }
+
+ if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
+ SkipUntil(tok::r_square, false);
+ Loc = Tok.getLocation();
+ if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
+ SkipUntil(tok::r_square, false);
+
+ CXX0XAttributeList Attr (CurrAttr, SourceRange(StartLoc, Loc), true);
+ return Attr;
+}
+
+/// ParseCXX0XAlignArgument - Parse the argument to C++0x's [[align]]
+/// attribute.
+///
+/// FIXME: Simply returns an alignof() expression if the argument is a
+/// type. Ideally, the type should be propagated directly into Sema.
+///
+/// [C++0x] 'align' '(' type-id ')'
+/// [C++0x] 'align' '(' assignment-expression ')'
+Parser::OwningExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) {
+ if (isTypeIdInParens()) {
+ EnterExpressionEvaluationContext Unevaluated(Actions,
+ Action::Unevaluated);
+ SourceLocation TypeLoc = Tok.getLocation();
+ TypeTy *Ty = ParseTypeName().get();
+ SourceRange TypeRange(Start, Tok.getLocation());
+ return Actions.ActOnSizeOfAlignOfExpr(TypeLoc, false, true, Ty,
+ TypeRange);
+ } else
+ return ParseConstantExpression();
+}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index d2b3b84..f780cf1 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -413,12 +413,12 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
///
Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
- bool parseParenAsExprList){
+ TypeTy *TypeOfCast) {
bool NotCastExpr;
OwningExprResult Res = ParseCastExpression(isUnaryExpression,
isAddressOfOperand,
NotCastExpr,
- parseParenAsExprList);
+ TypeOfCast);
if (NotCastExpr)
Diag(Tok, diag::err_expected_expression);
return move(Res);
@@ -538,7 +538,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
bool &NotCastExpr,
- bool parseParenAsExprList){
+ TypeTy *TypeOfCast) {
OwningExprResult Res(Actions);
tok::TokenKind SavedKind = Tok.getKind();
NotCastExpr = false;
@@ -563,7 +563,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
SourceLocation LParenLoc = Tok.getLocation();
SourceLocation RParenLoc;
Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
- parseParenAsExprList, CastTy, RParenLoc);
+ TypeOfCast, CastTy, RParenLoc);
if (Res.isInvalid()) return move(Res);
switch (ParenExprType) {
@@ -1047,7 +1047,8 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
// operands.
EnterExpressionEvaluationContext Unevaluated(Actions,
Action::Unevaluated);
- Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, false,
+ Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
+ 0/*TypeOfCast*/,
CastTy, RParenLoc);
CastRange = SourceRange(LParenLoc, RParenLoc);
@@ -1304,7 +1305,7 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() {
///
Parser::OwningExprResult
Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
- bool parseAsExprList, TypeTy *&CastTy,
+ TypeTy *TypeOfCast, TypeTy *&CastTy,
SourceLocation &RParenLoc) {
assert(Tok.is(tok::l_paren) && "Not a paren expr!");
GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
@@ -1315,7 +1316,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
Diag(Tok, diag::ext_gnu_statement_expr);
- OwningStmtResult Stmt(ParseCompoundStatement(true));
+ OwningStmtResult Stmt(ParseCompoundStatement(0, true));
ExprType = CompoundStmt;
// If the substmt parsed correctly, build the AST node.
@@ -1365,7 +1366,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// Parse the cast-expression that follows it next.
// TODO: For cast expression with CastTy.
- Result = ParseCastExpression(false, false, true);
+ Result = ParseCastExpression(false, false, CastTy);
if (!Result.isInvalid())
Result = Actions.ActOnCastExpr(CurScope, OpenLoc, CastTy, RParenLoc,
move(Result));
@@ -1374,15 +1375,15 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
return ExprError();
- } else if (parseAsExprList) {
+ } else if (TypeOfCast) {
// Parse the expression-list.
ExprVector ArgExprs(Actions);
CommaLocsTy CommaLocs;
if (!ParseExpressionList(ArgExprs, CommaLocs)) {
ExprType = SimpleExpr;
- Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
- move_arg(ArgExprs));
+ Result = Actions.ActOnParenOrParenListExpr(OpenLoc, Tok.getLocation(),
+ move_arg(ArgExprs), TypeOfCast);
}
} else {
Result = ParseExpression();
@@ -1503,7 +1504,7 @@ void Parser::ParseBlockId() {
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
DeclaratorInfo.AddAttributes(AttrList, Loc);
}
@@ -1565,7 +1566,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
ParamInfo.AddAttributes(AttrList, Loc);
}
@@ -1586,7 +1587,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
ParamInfo.AddAttributes(AttrList, Loc);
}
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index b2ecc9e..52003e6 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -124,7 +124,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
break;
}
- if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId) {
+ if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId &&
+ TemplateName.getKind() != UnqualifiedId::IK_LiteralOperatorId) {
Diag(TemplateName.getSourceRange().getBegin(),
diag::err_id_after_template_in_nested_name_spec)
<< TemplateName.getSourceRange();
@@ -148,7 +149,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
TPA.Commit();
TemplateTy Template
= Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName,
- ObjectType);
+ ObjectType, EnteringContext);
if (!Template)
break;
if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
@@ -326,6 +327,24 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
/*ObjectType=*/0,
Name))
return ExprError();
+
+ // This is only the direct operand of an & operator if it is not
+ // followed by a postfix-expression suffix.
+ if (isAddressOfOperand) {
+ switch (Tok.getKind()) {
+ case tok::l_square:
+ case tok::l_paren:
+ case tok::arrow:
+ case tok::period:
+ case tok::plusplus:
+ case tok::minusminus:
+ isAddressOfOperand = false;
+ break;
+
+ default:
+ break;
+ }
+ }
return Actions.ActOnIdExpression(CurScope, SS, Name, Tok.is(tok::l_paren),
isAddressOfOperand);
@@ -531,7 +550,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
CommaLocs.data(), RParenLoc);
}
-/// ParseCXXCondition - if/switch/while/for condition expression.
+/// ParseCXXCondition - if/switch/while condition expression.
///
/// condition:
/// expression
@@ -539,11 +558,20 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
/// '=' assignment-expression
///
-Parser::OwningExprResult Parser::ParseCXXCondition() {
- if (!isCXXConditionDeclaration())
- return ParseExpression(); // expression
-
- SourceLocation StartLoc = Tok.getLocation();
+/// \param ExprResult if the condition was parsed as an expression, the
+/// parsed expression.
+///
+/// \param DeclResult if the condition was parsed as a declaration, the
+/// parsed declaration.
+///
+/// \returns true if there was a parsing, false otherwise.
+bool Parser::ParseCXXCondition(OwningExprResult &ExprResult,
+ DeclPtrTy &DeclResult) {
+ if (!isCXXConditionDeclaration()) {
+ ExprResult = ParseExpression(); // expression
+ DeclResult = DeclPtrTy();
+ return ExprResult.isInvalid();
+ }
// type-specifier-seq
DeclSpec DS;
@@ -559,7 +587,7 @@ Parser::OwningExprResult Parser::ParseCXXCondition() {
OwningExprResult AsmLabel(ParseSimpleAsm(&Loc));
if (AsmLabel.isInvalid()) {
SkipUntil(tok::semi);
- return ExprError();
+ return true;
}
DeclaratorInfo.setAsmLabel(AsmLabel.release());
DeclaratorInfo.SetRangeEnd(Loc);
@@ -568,21 +596,28 @@ Parser::OwningExprResult Parser::ParseCXXCondition() {
// If attributes are present, parse them.
if (Tok.is(tok::kw___attribute)) {
SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
+ AttributeList *AttrList = ParseGNUAttributes(&Loc);
DeclaratorInfo.AddAttributes(AttrList, Loc);
}
+ // Type-check the declaration itself.
+ Action::DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(CurScope,
+ DeclaratorInfo);
+ DeclResult = Dcl.get();
+ ExprResult = ExprError();
+
// '=' assignment-expression
- if (Tok.isNot(tok::equal))
- return ExprError(Diag(Tok, diag::err_expected_equal_after_declarator));
- SourceLocation EqualLoc = ConsumeToken();
- OwningExprResult AssignExpr(ParseAssignmentExpression());
- if (AssignExpr.isInvalid())
- return ExprError();
-
- return Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc,
- DeclaratorInfo,EqualLoc,
- move(AssignExpr));
+ if (Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = ConsumeToken();
+ OwningExprResult AssignExpr(ParseAssignmentExpression());
+ if (!AssignExpr.isInvalid())
+ Actions.AddInitializerToDecl(DeclResult, move(AssignExpr));
+ } else {
+ // FIXME: C++0x allows a braced-init-list
+ Diag(Tok, diag::err_expected_equal_after_declarator);
+ }
+
+ return false;
}
/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
@@ -757,6 +792,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
switch (Id.getKind()) {
case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_OperatorFunctionId:
+ case UnqualifiedId::IK_LiteralOperatorId:
TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, EnteringContext,
Template);
break;
@@ -774,7 +810,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
TemplateName.setIdentifier(Name, NameLoc);
if (ObjectType) {
Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS,
- TemplateName, ObjectType);
+ TemplateName, ObjectType,
+ EnteringContext);
TNK = TNK_Dependent_template_name;
if (!Template.get())
return true;
@@ -813,7 +850,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
return true;
if (Id.getKind() == UnqualifiedId::IK_Identifier ||
- Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) {
+ Id.getKind() == UnqualifiedId::IK_OperatorFunctionId ||
+ Id.getKind() == UnqualifiedId::IK_LiteralOperatorId) {
// Form a parsed representation of the template-id to be stored in the
// UnqualifiedId.
TemplateIdAnnotation *TemplateId
@@ -996,6 +1034,26 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations);
return false;
}
+
+ // Parse a literal-operator-id.
+ //
+ // literal-operator-id: [C++0x 13.5.8]
+ // operator "" identifier
+
+ if (getLang().CPlusPlus0x && Tok.is(tok::string_literal)) {
+ if (Tok.getLength() != 2)
+ Diag(Tok.getLocation(), diag::err_operator_string_not_empty);
+ ConsumeStringToken();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected_ident);
+ return true;
+ }
+
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ Result.setLiteralOperatorId(II, KeywordLoc, ConsumeToken());
+ return false;
+ }
// Parse a conversion-function-id.
//
@@ -1010,7 +1068,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// Parse the type-specifier-seq.
DeclSpec DS;
- if (ParseCXXTypeSpecifierSeq(DS))
+ if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType?
return true;
// Parse the conversion-declarator, which is merely a sequence of
@@ -1111,12 +1169,13 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result))
return true;
- // If we have an operator-function-id and the next token is a '<', we may
- // have a
+ // If we have an operator-function-id or a literal-operator-id and the next
+ // token is a '<', we may have a
//
// template-id:
// operator-function-id < template-argument-list[opt] >
- if (Result.getKind() == UnqualifiedId::IK_OperatorFunctionId &&
+ if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId ||
+ Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) &&
Tok.is(tok::less))
return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(),
EnteringContext, ObjectType,
@@ -1152,7 +1211,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// Note that this is a destructor name.
Action::TypeTy *Ty = Actions.getTypeName(*ClassName, ClassNameLoc,
- CurScope, &SS);
+ CurScope, &SS, false, ObjectType);
if (!Ty) {
if (ObjectType)
Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 5ba1dd1..295625a 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -282,7 +282,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
// FIXME: as the name implies, this rule allows function definitions.
// We could pass a flag or check for functions during semantic analysis.
- allTUVariables.push_back(ParseDeclarationOrFunctionDefinition());
+ allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(0));
continue;
}
@@ -759,7 +759,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// If attributes exist after the method, parse them.
AttributeList *MethodAttrs = 0;
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
- MethodAttrs = ParseAttributes();
+ MethodAttrs = ParseGNUAttributes();
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
DeclPtrTy Result
@@ -791,7 +791,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// If attributes exist before the argument name, parse them.
ArgInfo.ArgAttrs = 0;
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
- ArgInfo.ArgAttrs = ParseAttributes();
+ ArgInfo.ArgAttrs = ParseGNUAttributes();
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); // missing argument name.
@@ -835,7 +835,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// If attributes exist after the method, parse them.
AttributeList *MethodAttrs = 0;
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
- MethodAttrs = ParseAttributes();
+ MethodAttrs = ParseGNUAttributes();
if (KeyIdents.size() == 0)
return DeclPtrTy();
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 7637382..c87010e 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -78,6 +78,10 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
const char *SemiError = 0;
OwningStmtResult Res(Actions);
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ Attr = ParseCXX0XAttributes();
+
// Cases in this switch statement should fall through if the parser expects
// the token to end in a semicolon (in which case SemiError should be set),
// or they directly 'return;' if not.
@@ -98,14 +102,15 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
case tok::identifier:
if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
// identifier ':' statement
- return ParseLabeledStatement();
+ return ParseLabeledStatement(Attr.AttrList);
}
// PASS THROUGH.
default: {
if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd);
+ DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd,
+ Attr);
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
}
@@ -114,6 +119,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
return StmtError();
}
+ // FIXME: Use the attributes
// expression[opt] ';'
OwningExprResult Expr(ParseExpression());
if (Expr.isInvalid()) {
@@ -129,47 +135,50 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
}
case tok::kw_case: // C99 6.8.1: labeled-statement
- return ParseCaseStatement();
+ return ParseCaseStatement(Attr.AttrList);
case tok::kw_default: // C99 6.8.1: labeled-statement
- return ParseDefaultStatement();
+ return ParseDefaultStatement(Attr.AttrList);
case tok::l_brace: // C99 6.8.2: compound-statement
- return ParseCompoundStatement();
+ return ParseCompoundStatement(Attr.AttrList);
case tok::semi: // C99 6.8.3p3: expression[opt] ';'
return Actions.ActOnNullStmt(ConsumeToken());
case tok::kw_if: // C99 6.8.4.1: if-statement
- return ParseIfStatement();
+ return ParseIfStatement(Attr.AttrList);
case tok::kw_switch: // C99 6.8.4.2: switch-statement
- return ParseSwitchStatement();
+ return ParseSwitchStatement(Attr.AttrList);
case tok::kw_while: // C99 6.8.5.1: while-statement
- return ParseWhileStatement();
+ return ParseWhileStatement(Attr.AttrList);
case tok::kw_do: // C99 6.8.5.2: do-statement
- Res = ParseDoStatement();
+ Res = ParseDoStatement(Attr.AttrList);
SemiError = "do/while";
break;
case tok::kw_for: // C99 6.8.5.3: for-statement
- return ParseForStatement();
+ return ParseForStatement(Attr.AttrList);
case tok::kw_goto: // C99 6.8.6.1: goto-statement
- Res = ParseGotoStatement();
+ Res = ParseGotoStatement(Attr.AttrList);
SemiError = "goto";
break;
case tok::kw_continue: // C99 6.8.6.2: continue-statement
- Res = ParseContinueStatement();
+ Res = ParseContinueStatement(Attr.AttrList);
SemiError = "continue";
break;
case tok::kw_break: // C99 6.8.6.3: break-statement
- Res = ParseBreakStatement();
+ Res = ParseBreakStatement(Attr.AttrList);
SemiError = "break";
break;
case tok::kw_return: // C99 6.8.6.4: return-statement
- Res = ParseReturnStatement();
+ Res = ParseReturnStatement(Attr.AttrList);
SemiError = "return";
break;
case tok::kw_asm: {
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
bool msAsm = false;
Res = ParseAsmStatement(msAsm);
if (msAsm) return move(Res);
@@ -178,7 +187,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
}
case tok::kw_try: // C++ 15: try-block
- return ParseCXXTryBlock();
+ return ParseCXXTryBlock(Attr.AttrList);
}
// If we reached this code, the statement must end in a semicolon.
@@ -202,7 +211,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
/// identifier ':' statement
/// [GNU] identifier ':' attributes[opt] statement
///
-Parser::OwningStmtResult Parser::ParseLabeledStatement() {
+Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) {
assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
"Not an identifier!");
@@ -215,10 +224,8 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement() {
SourceLocation ColonLoc = ConsumeToken();
// Read label attributes, if present.
- Action::AttrTy *AttrList = 0;
if (Tok.is(tok::kw___attribute))
- // TODO: save these somewhere.
- AttrList = ParseAttributes();
+ Attr = addAttributeLists(Attr, ParseGNUAttributes());
OwningStmtResult SubStmt(ParseStatement());
@@ -236,8 +243,9 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement() {
/// 'case' constant-expression ':' statement
/// [GNU] 'case' constant-expression '...' constant-expression ':' statement
///
-Parser::OwningStmtResult Parser::ParseCaseStatement() {
+Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) {
assert(Tok.is(tok::kw_case) && "Not a case stmt!");
+ // FIXME: Use attributes?
// It is very very common for code to contain many case statements recursively
// nested, as in (but usually without indentation):
@@ -354,7 +362,8 @@ Parser::OwningStmtResult Parser::ParseCaseStatement() {
/// 'default' ':' statement
/// Note that this does not parse the 'statement' at the end.
///
-Parser::OwningStmtResult Parser::ParseDefaultStatement() {
+Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) {
+ //FIXME: Use attributes?
assert(Tok.is(tok::kw_default) && "Not a default stmt!");
SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'.
@@ -408,7 +417,9 @@ Parser::OwningStmtResult Parser::ParseDefaultStatement() {
/// [OMP] barrier-directive
/// [OMP] flush-directive
///
-Parser::OwningStmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
+Parser::OwningStmtResult Parser::ParseCompoundStatement(AttributeList *Attr,
+ bool isStmtExpr) {
+ //FIXME: Use attributes?
assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
// Enter a scope to hold everything within the compound stmt. Compound
@@ -449,6 +460,10 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
while (Tok.is(tok::kw___extension__))
ConsumeToken();
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ Attr = ParseCXX0XAttributes();
+
// If this is the start of a declaration, parse it as such.
if (isDeclarationStatement()) {
// __extension__ silences extension warnings in the subdeclaration.
@@ -456,7 +471,8 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
ExtensionRAIIObject O(Diags);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext,DeclEnd);
+ DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext, DeclEnd,
+ Attr);
R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
} else {
// Otherwise this was a unary __extension__ marker.
@@ -467,6 +483,7 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
continue;
}
+ // FIXME: Use attributes?
// Eat the semicolon at the end of stmt and convert the expr into a
// statement.
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
@@ -500,22 +517,22 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
/// should try to recover harder. It returns false if the condition is
/// successfully parsed. Note that a successful parse can still have semantic
/// errors in the condition.
-bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp,
- bool OnlyAllowCondition,
- SourceLocation *LParenLocPtr,
- SourceLocation *RParenLocPtr) {
+bool Parser::ParseParenExprOrCondition(OwningExprResult &ExprResult,
+ DeclPtrTy &DeclResult) {
+ bool ParseError = false;
+
SourceLocation LParenLoc = ConsumeParen();
- if (LParenLocPtr) *LParenLocPtr = LParenLoc;
-
- if (getLang().CPlusPlus)
- CondExp = ParseCXXCondition();
- else
- CondExp = ParseExpression();
+ if (getLang().CPlusPlus)
+ ParseError = ParseCXXCondition(ExprResult, DeclResult);
+ else {
+ ExprResult = ParseExpression();
+ DeclResult = DeclPtrTy();
+ }
// If the parser was confused by the condition and we don't have a ')', try to
// recover by skipping ahead to a semi and bailing out. If condexp is
// semantically invalid but we have well formed code, keep going.
- if (CondExp.isInvalid() && Tok.isNot(tok::r_paren)) {
+ if (ExprResult.isInvalid() && !DeclResult.get() && Tok.isNot(tok::r_paren)) {
SkipUntil(tok::semi);
// Skipping may have stopped if it found the containing ')'. If so, we can
// continue parsing the if statement.
@@ -524,8 +541,7 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp,
}
// Otherwise the condition is valid or the rparen is present.
- SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- if (RParenLocPtr) *RParenLocPtr = RPLoc;
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
return false;
}
@@ -537,7 +553,8 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp,
/// [C++] 'if' '(' condition ')' statement
/// [C++] 'if' '(' condition ')' statement 'else' statement
///
-Parser::OwningStmtResult Parser::ParseIfStatement() {
+Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_if) && "Not an if stmt!");
SourceLocation IfLoc = ConsumeToken(); // eat the 'if'.
@@ -565,7 +582,8 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
// Parse the condition.
OwningExprResult CondExp(Actions);
- if (ParseParenExprOrCondition(CondExp))
+ DeclPtrTy CondVar;
+ if (ParseParenExprOrCondition(CondExp, CondVar))
return StmtError();
FullExprArg FullCondExp(Actions.FullExpr(CondExp));
@@ -632,7 +650,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
// If the condition was invalid, discard the if statement. We could recover
// better by replacing it with a valid expr, but don't do that yet.
- if (CondExp.isInvalid())
+ if (CondExp.isInvalid() && !CondVar.get())
return StmtError();
// If the then or else stmt is invalid and the other is valid (and present),
@@ -651,7 +669,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
if (ElseStmt.isInvalid())
ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
- return Actions.ActOnIfStmt(IfLoc, FullCondExp, move(ThenStmt),
+ return Actions.ActOnIfStmt(IfLoc, FullCondExp, CondVar, move(ThenStmt),
ElseLoc, move(ElseStmt));
}
@@ -659,7 +677,8 @@ Parser::OwningStmtResult Parser::ParseIfStatement() {
/// switch-statement:
/// 'switch' '(' expression ')' statement
/// [C++] 'switch' '(' condition ')' statement
-Parser::OwningStmtResult Parser::ParseSwitchStatement() {
+Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'.
@@ -690,12 +709,13 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() {
// Parse the condition.
OwningExprResult Cond(Actions);
- if (ParseParenExprOrCondition(Cond))
+ DeclPtrTy CondVar;
+ if (ParseParenExprOrCondition(Cond, CondVar))
return StmtError();
- OwningStmtResult Switch(Actions);
- if (!Cond.isInvalid())
- Switch = Actions.ActOnStartOfSwitchStmt(move(Cond));
+ FullExprArg FullCond(Actions.FullExpr(Cond));
+
+ OwningStmtResult Switch = Actions.ActOnStartOfSwitchStmt(FullCond, CondVar);
// C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
@@ -724,7 +744,7 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() {
SwitchScope.Exit();
- if (Cond.isInvalid())
+ if (Cond.isInvalid() && !CondVar.get())
return StmtError();
return Actions.ActOnFinishSwitchStmt(SwitchLoc, move(Switch), move(Body));
@@ -734,7 +754,8 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() {
/// while-statement: [C99 6.8.5.1]
/// 'while' '(' expression ')' statement
/// [C++] 'while' '(' condition ')' statement
-Parser::OwningStmtResult Parser::ParseWhileStatement() {
+Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_while) && "Not a while stmt!");
SourceLocation WhileLoc = Tok.getLocation();
ConsumeToken(); // eat the 'while'.
@@ -769,7 +790,8 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() {
// Parse the condition.
OwningExprResult Cond(Actions);
- if (ParseParenExprOrCondition(Cond))
+ DeclPtrTy CondVar;
+ if (ParseParenExprOrCondition(Cond, CondVar))
return StmtError();
FullExprArg FullCond(Actions.FullExpr(Cond));
@@ -795,17 +817,18 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() {
InnerScope.Exit();
WhileScope.Exit();
- if (Cond.isInvalid() || Body.isInvalid())
+ if ((Cond.isInvalid() && !CondVar.get()) || Body.isInvalid())
return StmtError();
- return Actions.ActOnWhileStmt(WhileLoc, FullCond, move(Body));
+ return Actions.ActOnWhileStmt(WhileLoc, FullCond, CondVar, move(Body));
}
/// ParseDoStatement
/// do-statement: [C99 6.8.5.2]
/// 'do' statement 'while' '(' expression ')' ';'
/// Note: this lets the caller parse the end ';'.
-Parser::OwningStmtResult Parser::ParseDoStatement() {
+Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_do) && "Not a do stmt!");
SourceLocation DoLoc = ConsumeToken(); // eat the 'do'.
@@ -854,10 +877,9 @@ Parser::OwningStmtResult Parser::ParseDoStatement() {
}
// Parse the parenthesized condition.
- OwningExprResult Cond(Actions);
- SourceLocation LPLoc, RPLoc;
- ParseParenExprOrCondition(Cond, true, &LPLoc, &RPLoc);
-
+ SourceLocation LPLoc = ConsumeParen();
+ OwningExprResult Cond = ParseExpression();
+ SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LPLoc);
DoScope.Exit();
if (Cond.isInvalid() || Body.isInvalid())
@@ -880,7 +902,8 @@ Parser::OwningStmtResult Parser::ParseDoStatement() {
/// [C++] expression-statement
/// [C++] simple-declaration
///
-Parser::OwningStmtResult Parser::ParseForStatement() {
+Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_for) && "Not a for stmt!");
SourceLocation ForLoc = ConsumeToken(); // eat the 'for'.
@@ -922,7 +945,8 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
bool ForEach = false;
OwningStmtResult FirstPart(Actions);
OwningExprResult SecondPart(Actions), ThirdPart(Actions);
-
+ DeclPtrTy SecondVar;
+
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(CurScope);
ConsumeToken();
@@ -937,13 +961,19 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode?
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
+ AttributeList *AttrList = 0;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ AttrList = ParseCXX0XAttributes().AttrList;
+
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd);
+ DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd,
+ AttrList);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
if (Tok.is(tok::semi)) { // for (int x = 4;
ConsumeToken();
} else if ((ForEach = isTokIdentifier_in())) {
+ Actions.ActOnForEachDeclStmt(DG);
// ObjC: for (id x in expr)
ConsumeToken(); // consume 'in'
SecondPart = ParseExpression();
@@ -974,13 +1004,17 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
if (Tok.is(tok::semi)) { // for (...;;
// no second part.
} else {
- SecondPart =getLang().CPlusPlus ? ParseCXXCondition() : ParseExpression();
+ if (getLang().CPlusPlus)
+ ParseCXXCondition(SecondPart, SecondVar);
+ else
+ SecondPart = ParseExpression();
}
if (Tok.is(tok::semi)) {
ConsumeToken();
} else {
- if (!SecondPart.isInvalid()) Diag(Tok, diag::err_expected_semi_for);
+ if (!SecondPart.isInvalid() || SecondVar.get())
+ Diag(Tok, diag::err_expected_semi_for);
SkipUntil(tok::semi);
}
@@ -1019,8 +1053,9 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
if (!ForEach)
return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart),
- move(SecondPart), move(ThirdPart),
- RParenLoc, move(Body));
+ Actions.FullExpr(SecondPart), SecondVar,
+ Actions.FullExpr(ThirdPart), RParenLoc,
+ move(Body));
return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
move(FirstPart),
@@ -1035,7 +1070,8 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
///
/// Note: this lets the caller parse the end ';'.
///
-Parser::OwningStmtResult Parser::ParseGotoStatement() {
+Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_goto) && "Not a goto stmt!");
SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'.
@@ -1068,7 +1104,8 @@ Parser::OwningStmtResult Parser::ParseGotoStatement() {
///
/// Note: this lets the caller parse the end ';'.
///
-Parser::OwningStmtResult Parser::ParseContinueStatement() {
+Parser::OwningStmtResult Parser::ParseContinueStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'.
return Actions.ActOnContinueStmt(ContinueLoc, CurScope);
}
@@ -1079,7 +1116,8 @@ Parser::OwningStmtResult Parser::ParseContinueStatement() {
///
/// Note: this lets the caller parse the end ';'.
///
-Parser::OwningStmtResult Parser::ParseBreakStatement() {
+Parser::OwningStmtResult Parser::ParseBreakStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'.
return Actions.ActOnBreakStmt(BreakLoc, CurScope);
}
@@ -1087,7 +1125,8 @@ Parser::OwningStmtResult Parser::ParseBreakStatement() {
/// ParseReturnStatement
/// jump-statement:
/// 'return' expression[opt] ';'
-Parser::OwningStmtResult Parser::ParseReturnStatement() {
+Parser::OwningStmtResult Parser::ParseReturnStatement(AttributeList *Attr) {
+ // FIXME: Use attributes?
assert(Tok.is(tok::kw_return) && "Not a return stmt!");
SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'.
@@ -1163,7 +1202,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) {
}
DeclSpec DS;
SourceLocation Loc = Tok.getLocation();
- ParseTypeQualifierListOpt(DS);
+ ParseTypeQualifierListOpt(DS, true, false);
// GNU asms accept, but warn, about type-qualifiers other than volatile.
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
@@ -1371,7 +1410,8 @@ Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) {
/// try-block:
/// 'try' compound-statement handler-seq
///
-Parser::OwningStmtResult Parser::ParseCXXTryBlock() {
+Parser::OwningStmtResult Parser::ParseCXXTryBlock(AttributeList* Attr) {
+ // FIXME: Add attributes?
assert(Tok.is(tok::kw_try) && "Expected 'try'");
SourceLocation TryLoc = ConsumeToken();
@@ -1393,11 +1433,17 @@ Parser::OwningStmtResult Parser::ParseCXXTryBlock() {
Parser::OwningStmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected_lbrace));
- OwningStmtResult TryBlock(ParseCompoundStatement());
+ // FIXME: Possible draft standard bug: attribute-specifier should be allowed?
+ OwningStmtResult TryBlock(ParseCompoundStatement(0));
if (TryBlock.isInvalid())
return move(TryBlock);
StmtVector Handlers(Actions);
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ CXX0XAttributeList Attr = ParseCXX0XAttributes();
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
+ }
if (Tok.isNot(tok::kw_catch))
return StmtError(Diag(Tok, diag::err_expected_catch));
while (Tok.is(tok::kw_catch)) {
@@ -1457,7 +1503,8 @@ Parser::OwningStmtResult Parser::ParseCXXCatchBlock() {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected_lbrace));
- OwningStmtResult Block(ParseCompoundStatement());
+ // FIXME: Possible draft standard bug: attribute-specifier should be allowed?
+ OwningStmtResult Block(ParseCompoundStatement(0));
if (Block.isInvalid())
return move(Block);
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 16b1c80..0dbf37c 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -16,7 +16,6 @@
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "clang/Parse/Template.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
/// \brief Parse a template declaration, explicit instantiation, or
@@ -34,7 +33,7 @@ Parser::ParseDeclarationStartingWithTemplate(unsigned Context,
/// \brief RAII class that manages the template parameter depth.
namespace {
- class VISIBILITY_HIDDEN TemplateParameterDepthCounter {
+ class TemplateParameterDepthCounter {
unsigned &Depth;
unsigned AddedLevels;
@@ -192,6 +191,10 @@ Parser::ParseSingleDeclarationAfterTemplate(
// Parse the declaration specifiers.
ParsingDeclSpec DS(*this);
+
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ DS.AddAttributes(ParseCXX0XAttributes().AttrList);
+
ParseDeclarationSpecifiers(DS, TemplateInfo, AS);
if (Tok.is(tok::semi)) {
@@ -333,6 +336,40 @@ Parser::ParseTemplateParameterList(unsigned Depth,
return true;
}
+/// \brief Determine whether the parser is at the start of a template
+/// type parameter.
+bool Parser::isStartOfTemplateTypeParameter() {
+ if (Tok.is(tok::kw_class))
+ return true;
+
+ if (Tok.isNot(tok::kw_typename))
+ return false;
+
+ // C++ [temp.param]p2:
+ // There is no semantic difference between class and typename in a
+ // template-parameter. typename followed by an unqualified-id
+ // names a template type parameter. typename followed by a
+ // qualified-id denotes the type in a non-type
+ // parameter-declaration.
+ Token Next = NextToken();
+
+ // If we have an identifier, skip over it.
+ if (Next.getKind() == tok::identifier)
+ Next = GetLookAheadToken(2);
+
+ switch (Next.getKind()) {
+ case tok::equal:
+ case tok::comma:
+ case tok::greater:
+ case tok::greatergreater:
+ case tok::ellipsis:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
/// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]).
///
/// template-parameter: [C++ temp.param]
@@ -348,12 +385,8 @@ Parser::ParseTemplateParameterList(unsigned Depth,
/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
Parser::DeclPtrTy
Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
- if (Tok.is(tok::kw_class) ||
- (Tok.is(tok::kw_typename) &&
- // FIXME: Next token has not been annotated!
- NextToken().isNot(tok::annot_typename))) {
+ if (isStartOfTemplateTypeParameter())
return ParseTypeParameter(Depth, Position);
- }
if (Tok.is(tok::kw_template))
return ParseTemplateTemplateParameter(Depth, Position);
@@ -851,7 +884,8 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
if (isEndOfTemplateArgument(Tok)) {
TemplateTy Template
= Actions.ActOnDependentTemplateName(TemplateLoc, SS, Name,
- /*ObjectType=*/0);
+ /*ObjectType=*/0,
+ /*EnteringContext=*/false);
if (Template.get())
return ParsedTemplateArgument(SS, Template, Name.StartLocation);
}
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 7ac2977..dabd065 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -55,12 +55,11 @@ bool Parser::isCXXDeclarationStatement() {
// using-declaration
// using-directive
case tok::kw_using:
- return true;
- case tok::kw_static_assert:
// static_assert-declaration
+ case tok::kw_static_assert:
return true;
- default:
// simple-declaration
+ default:
return isCXXSimpleDeclaration();
}
}
@@ -351,6 +350,89 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
return TPR == TPResult::True();
}
+/// isCXX0XAttributeSpecifier - returns true if this is a C++0x
+/// attribute-specifier. By default, unless in Obj-C++, only a cursory check is
+/// performed that will simply return true if a [[ is seen. Currently C++ has no
+/// syntactical ambiguities from this check, but it may inhibit error recovery.
+/// If CheckClosing is true, a check is made for closing ]] brackets.
+///
+/// If given, After is set to the token after the attribute-specifier so that
+/// appropriate parsing decisions can be made; it is left untouched if false is
+/// returned.
+///
+/// FIXME: If an error is in the closing ]] brackets, the program assumes
+/// the absence of an attribute-specifier, which can cause very yucky errors
+/// to occur.
+///
+/// [C++0x] attribute-specifier:
+/// '[' '[' attribute-list ']' ']'
+///
+/// [C++0x] attribute-list:
+/// attribute[opt]
+/// attribute-list ',' attribute[opt]
+///
+/// [C++0x] attribute:
+/// attribute-token attribute-argument-clause[opt]
+///
+/// [C++0x] attribute-token:
+/// identifier
+/// attribute-scoped-token
+///
+/// [C++0x] attribute-scoped-token:
+/// attribute-namespace '::' identifier
+///
+/// [C++0x] attribute-namespace:
+/// identifier
+///
+/// [C++0x] attribute-argument-clause:
+/// '(' balanced-token-seq ')'
+///
+/// [C++0x] balanced-token-seq:
+/// balanced-token
+/// balanced-token-seq balanced-token
+///
+/// [C++0x] balanced-token:
+/// '(' balanced-token-seq ')'
+/// '[' balanced-token-seq ']'
+/// '{' balanced-token-seq '}'
+/// any token but '(', ')', '[', ']', '{', or '}'
+bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing,
+ tok::TokenKind *After) {
+ if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square))
+ return false;
+
+ // No tentative parsing if we don't need to look for ]]
+ if (!CheckClosing && !getLang().ObjC1)
+ return true;
+
+ struct TentativeReverter {
+ TentativeParsingAction PA;
+
+ TentativeReverter (Parser& P)
+ : PA(P)
+ {}
+ ~TentativeReverter () {
+ PA.Revert();
+ }
+ } R(*this);
+
+ // Opening brackets were checked for above.
+ ConsumeBracket();
+ ConsumeBracket();
+
+ // SkipUntil will handle balanced tokens, which are guaranteed in attributes.
+ SkipUntil(tok::r_square, false);
+
+ if (Tok.isNot(tok::r_square))
+ return false;
+ ConsumeBracket();
+
+ if (After)
+ *After = Tok.getKind();
+
+ return true;
+}
+
/// declarator:
/// direct-declarator
/// ptr-operator declarator
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index a915274..e321564 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -355,7 +355,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
return true;
}
- Result = ParseExternalDeclaration();
+ CXX0XAttributeList Attr;
+ if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+ Attr = ParseCXX0XAttributes();
+ Result = ParseExternalDeclaration(Attr);
return false;
}
@@ -396,7 +399,7 @@ void Parser::ParseTranslationUnit() {
/// ';'
///
/// [C++0x/GNU] 'extern' 'template' declaration
-Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
+Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) {
DeclPtrTy SingleDecl;
switch (Tok.getKind()) {
case tok::semi:
@@ -418,9 +421,13 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
// __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this.
ConsumeToken();
- return ParseExternalDeclaration();
+ return ParseExternalDeclaration(Attr);
}
case tok::kw_asm: {
+ if (Attr.HasAttr)
+ Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+ << Attr.Range;
+
OwningExprResult Result(ParseSimpleAsm());
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
@@ -449,7 +456,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
case tok::code_completion:
Actions.CodeCompleteOrdinaryName(CurScope);
ConsumeToken();
- return ParseExternalDeclaration();
+ return ParseExternalDeclaration(Attr);
case tok::kw_using:
case tok::kw_namespace:
case tok::kw_typedef:
@@ -459,7 +466,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
// A function definition cannot start with a these keywords.
{
SourceLocation DeclEnd;
- return ParseDeclaration(Declarator::FileContext, DeclEnd);
+ return ParseDeclaration(Declarator::FileContext, DeclEnd, Attr);
}
case tok::kw_extern:
if (getLang().CPlusPlus && NextToken().is(tok::kw_template)) {
@@ -477,7 +484,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
default:
// We can't tell whether this is a function-definition or declaration yet.
- return ParseDeclarationOrFunctionDefinition();
+ return ParseDeclarationOrFunctionDefinition(Attr.AttrList);
}
// This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -525,9 +532,13 @@ bool Parser::isStartOfFunctionDefinition() {
/// [OMP] threadprivate-directive [TODO]
///
Parser::DeclGroupPtrTy
-Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
+Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr,
+ AccessSpecifier AS) {
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
+ if (Attr)
+ DS.AddAttributes(Attr);
+
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
@@ -719,7 +730,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
// If attributes are present, parse them.
if (Tok.is(tok::kw___attribute))
// FIXME: attach attributes too.
- AttrList = ParseAttributes();
+ AttrList = ParseGNUAttributes();
// Ask the actions module to compute the type for this declarator.
Action::DeclPtrTy Param =
OpenPOWER on IntegriCloud