summaryrefslogtreecommitdiffstats
path: root/lib/Parse/ParseDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Parse/ParseDecl.cpp')
-rw-r--r--lib/Parse/ParseDecl.cpp256
1 files changed, 204 insertions, 52 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 990a909..6a87b78 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -178,6 +178,12 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
}
}
+/// \brief Determine whether the given attribute has all expression arguments.
+static bool attributeHasExprArgs(const IdentifierInfo &II) {
+ return llvm::StringSwitch<bool>(II.getName())
+#include "clang/Parse/AttrExprArgs.inc"
+ .Default(false);
+}
/// Parse the arguments to a parameterized GNU attribute or
/// a C++11 attribute in "gnu" namespace.
@@ -247,6 +253,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
TypeParsed = true;
break;
}
+ // If the attribute has all expression arguments, and not a "parameter",
+ // break out to handle it below.
+ if (attributeHasExprArgs(*AttrName))
+ break;
ParmName = Tok.getIdentifierInfo();
ParmLoc = ConsumeToken();
break;
@@ -364,6 +374,7 @@ bool Parser::IsSimpleMicrosoftDeclSpec(IdentifierInfo *Ident) {
.Case("novtable", true)
.Case("selectany", true)
.Case("thread", true)
+ .Case("safebuffers", true )
.Default(false);
}
@@ -394,17 +405,119 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident,
// The property declspec is more complex in that it can take one or two
// assignment expressions as a parameter, but the lhs of the assignment
// must be named get or put.
- //
- // For right now, we will just skip to the closing right paren of the
- // property expression.
- //
- // FIXME: we should deal with __declspec(property) at some point because it
- // is used in the platform SDK headers for the Parallel Patterns Library
- // and ATL.
- BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen_after,
- Ident->getNameStart(), tok::r_paren))
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok.getLocation(), diag::err_expected_lparen_after)
+ << Ident->getNameStart();
return;
+ }
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.expectAndConsume(diag::err_expected_lparen_after,
+ Ident->getNameStart(), tok::r_paren);
+
+ enum AccessorKind {
+ AK_Invalid = -1,
+ AK_Put = 0, AK_Get = 1 // indices into AccessorNames
+ };
+ IdentifierInfo *AccessorNames[] = { 0, 0 };
+ bool HasInvalidAccessor = false;
+
+ // Parse the accessor specifications.
+ while (true) {
+ // Stop if this doesn't look like an accessor spec.
+ if (!Tok.is(tok::identifier)) {
+ // If the user wrote a completely empty list, use a special diagnostic.
+ if (Tok.is(tok::r_paren) && !HasInvalidAccessor &&
+ AccessorNames[AK_Put] == 0 && AccessorNames[AK_Get] == 0) {
+ Diag(Loc, diag::err_ms_property_no_getter_or_putter);
+ break;
+ }
+
+ Diag(Tok.getLocation(), diag::err_ms_property_unknown_accessor);
+ break;
+ }
+
+ AccessorKind Kind;
+ SourceLocation KindLoc = Tok.getLocation();
+ StringRef KindStr = Tok.getIdentifierInfo()->getName();
+ if (KindStr == "get") {
+ Kind = AK_Get;
+ } else if (KindStr == "put") {
+ Kind = AK_Put;
+
+ // Recover from the common mistake of using 'set' instead of 'put'.
+ } else if (KindStr == "set") {
+ Diag(KindLoc, diag::err_ms_property_has_set_accessor)
+ << FixItHint::CreateReplacement(KindLoc, "put");
+ Kind = AK_Put;
+
+ // Handle the mistake of forgetting the accessor kind by skipping
+ // this accessor.
+ } else if (NextToken().is(tok::comma) || NextToken().is(tok::r_paren)) {
+ Diag(KindLoc, diag::err_ms_property_missing_accessor_kind);
+ ConsumeToken();
+ HasInvalidAccessor = true;
+ goto next_property_accessor;
+
+ // Otherwise, complain about the unknown accessor kind.
+ } else {
+ Diag(KindLoc, diag::err_ms_property_unknown_accessor);
+ HasInvalidAccessor = true;
+ Kind = AK_Invalid;
+
+ // Try to keep parsing unless it doesn't look like an accessor spec.
+ if (!NextToken().is(tok::equal)) break;
+ }
+
+ // Consume the identifier.
+ ConsumeToken();
+
+ // Consume the '='.
+ if (Tok.is(tok::equal)) {
+ ConsumeToken();
+ } else {
+ Diag(Tok.getLocation(), diag::err_ms_property_expected_equal)
+ << KindStr;
+ break;
+ }
+
+ // Expect the method name.
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_ms_property_expected_accessor_name);
+ break;
+ }
+
+ if (Kind == AK_Invalid) {
+ // Just drop invalid accessors.
+ } else if (AccessorNames[Kind] != NULL) {
+ // Complain about the repeated accessor, ignore it, and keep parsing.
+ Diag(KindLoc, diag::err_ms_property_duplicate_accessor) << KindStr;
+ } else {
+ AccessorNames[Kind] = Tok.getIdentifierInfo();
+ }
+ ConsumeToken();
+
+ next_property_accessor:
+ // Keep processing accessors until we run out.
+ if (Tok.is(tok::comma)) {
+ ConsumeAnyToken();
+ continue;
+
+ // If we run into the ')', stop without consuming it.
+ } else if (Tok.is(tok::r_paren)) {
+ break;
+ } else {
+ Diag(Tok.getLocation(), diag::err_ms_property_expected_comma_or_rparen);
+ break;
+ }
+ }
+
+ // Only add the property attribute if it was well-formed.
+ if (!HasInvalidAccessor) {
+ Attrs.addNewPropertyAttr(Ident, Loc, 0, SourceLocation(), 0,
+ SourceLocation(),
+ AccessorNames[AK_Get], AccessorNames[AK_Put],
+ AttributeList::AS_Declspec);
+ }
T.skipToEnd();
} else {
// We don't recognize this as a valid declspec, but instead of creating the
@@ -1489,35 +1602,42 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
MaybeParseGNUAttributes(D, &LateParsedAttrs);
// Check to see if we have a function *definition* which must have a body.
- if (AllowFunctionDefinitions && D.isFunctionDeclarator() &&
+ if (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()) {
- if (isStartOfFunctionDefinition(D)) {
- if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
- Diag(Tok, diag::err_function_declared_typedef);
+ if (AllowFunctionDefinitions) {
+ if (isStartOfFunctionDefinition(D)) {
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ Diag(Tok, diag::err_function_declared_typedef);
- // Recover by treating the 'typedef' as spurious.
- DS.ClearStorageClassSpecs();
- }
+ // Recover by treating the 'typedef' as spurious.
+ DS.ClearStorageClassSpecs();
+ }
- Decl *TheDecl =
- ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs);
- return Actions.ConvertDeclToDeclGroup(TheDecl);
- }
+ Decl *TheDecl =
+ ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs);
+ return Actions.ConvertDeclToDeclGroup(TheDecl);
+ }
- 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.
+ 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.
+ } else {
+ Diag(Tok, diag::err_expected_fn_body);
+ SkipUntil(tok::semi);
+ return DeclGroupPtrTy();
+ }
} else {
- Diag(Tok, diag::err_expected_fn_body);
- SkipUntil(tok::semi);
- return DeclGroupPtrTy();
+ if (Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::err_function_definition_not_allowed);
+ SkipUntil(tok::r_brace, true, true);
+ }
}
}
@@ -1527,14 +1647,23 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// 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();
- if (Tok.is(tok::l_brace))
- FRI->RangeExpr = ParseBraceInitializer();
- else
- FRI->RangeExpr = ParseExpression();
+ //
+ // Handle the Objective-C for-in loop variable similarly, although we
+ // don't need to parse the container in advance.
+ if (FRI && (Tok.is(tok::colon) || isTokIdentifier_in())) {
+ bool IsForRangeLoop = false;
+ if (Tok.is(tok::colon)) {
+ IsForRangeLoop = true;
+ FRI->ColonLoc = ConsumeToken();
+ if (Tok.is(tok::l_brace))
+ FRI->RangeExpr = ParseBraceInitializer();
+ else
+ FRI->RangeExpr = ParseExpression();
+ }
+
Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
- Actions.ActOnCXXForRangeDecl(ThisDecl);
+ if (IsForRangeLoop)
+ Actions.ActOnCXXForRangeDecl(ThisDecl);
Actions.FinalizeDeclaration(ThisDecl);
D.complete(ThisDecl);
return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1);
@@ -1691,8 +1820,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
}
}
- bool TypeContainsAuto =
- D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
+ bool TypeContainsAuto = D.getDeclSpec().containsPlaceholderType();
// Parse declarator '=' initializer.
// If a '==' or '+=' is found, suggest a fixit to '='.
@@ -1839,7 +1967,8 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
if (DS.getStorageClassSpecLoc().isValid())
Diag(DS.getStorageClassSpecLoc(),diag::err_typename_invalid_storageclass);
else
- Diag(DS.getThreadSpecLoc(), diag::err_typename_invalid_storageclass);
+ Diag(DS.getThreadStorageClassSpecLoc(),
+ diag::err_typename_invalid_storageclass);
DS.ClearStorageClassSpecs();
}
@@ -1920,10 +2049,9 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
// 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.
+ // implicit int as an extension in C99 and C11.
if (DSC != DSC_type_specifier && DSC != DSC_trailing &&
- (!getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt) &&
+ !getLangOpts().CPlusPlus &&
isValidAfterIdentifierInDeclarator(NextToken())) {
// If this token is valid for implicit int, e.g. "static x = 4", then
// we just avoid eating the identifier, so it will be parsed as the
@@ -2172,6 +2300,8 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
/// 'auto'
/// 'register'
/// [C++] 'mutable'
+/// [C++11] 'thread_local'
+/// [C11] '_Thread_local'
/// [GNU] '__thread'
/// function-specifier: [C99 6.7.4]
/// [C99] 'inline'
@@ -2608,7 +2738,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
PrevSpec, DiagID);
break;
case tok::kw_extern:
- if (DS.isThreadSpecified())
+ if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread)
Diag(Tok, diag::ext_thread_before) << "extern";
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_extern, Loc,
PrevSpec, DiagID);
@@ -2618,7 +2748,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
Loc, PrevSpec, DiagID);
break;
case tok::kw_static:
- if (DS.isThreadSpecified())
+ if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread)
Diag(Tok, diag::ext_thread_before) << "static";
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc,
PrevSpec, DiagID);
@@ -2647,7 +2777,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
PrevSpec, DiagID);
break;
case tok::kw___thread:
- isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID);
+ isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS___thread, Loc,
+ PrevSpec, DiagID);
+ break;
+ case tok::kw_thread_local:
+ isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS_thread_local, Loc,
+ PrevSpec, DiagID);
+ break;
+ case tok::kw__Thread_local:
+ isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS__Thread_local,
+ Loc, PrevSpec, DiagID);
break;
// function-specifier
@@ -3100,6 +3239,16 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
continue;
}
+ if (Tok.is(tok::annot_pragma_pack)) {
+ HandlePragmaPack();
+ continue;
+ }
+
+ if (Tok.is(tok::annot_pragma_align)) {
+ HandlePragmaAlign();
+ continue;
+ }
+
if (!Tok.is(tok::at)) {
struct CFieldCallback : FieldCallback {
Parser &P;
@@ -3227,9 +3376,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
bool IsScopedUsingClassTag = false;
// In C++11, recognize 'enum class' and 'enum struct'.
- if (getLangOpts().CPlusPlus11 &&
- (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) {
- Diag(Tok, diag::warn_cxx98_compat_scoped_enum);
+ if (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct)) {
+ Diag(Tok, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_scoped_enum
+ : diag::ext_scoped_enum);
IsScopedUsingClassTag = Tok.is(tok::kw_class);
ScopedEnumKWLoc = ConsumeToken();
@@ -3614,8 +3763,8 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
MaybeParseGNUAttributes(attrs);
Actions.ActOnEnumBody(StartLoc, T.getOpenLocation(), T.getCloseLocation(),
- EnumDecl, EnumConstantDecls.data(),
- EnumConstantDecls.size(), getCurScope(),
+ EnumDecl, EnumConstantDecls,
+ getCurScope(),
attrs.getList());
EnumScope.Exit();
@@ -3894,6 +4043,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_auto:
case tok::kw_register:
case tok::kw___thread:
+ case tok::kw_thread_local:
+ case tok::kw__Thread_local:
// Modules
case tok::kw___module_private__:
@@ -4873,7 +5024,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
Sema::CXXThisScopeRAII ThisScope(Actions,
dyn_cast<CXXRecordDecl>(Actions.CurContext),
DS.getTypeQualifiers() |
- (D.getDeclSpec().isConstexprSpecified()
+ (D.getDeclSpec().isConstexprSpecified() &&
+ !getLangOpts().CPlusPlus1y
? Qualifiers::Const : 0),
IsCXX11MemberFunction);
OpenPOWER on IntegriCloud