diff options
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/CMakeLists.txt | 2 | ||||
-rw-r--r-- | lib/Parse/ParseAST.cpp | 19 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 72 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 326 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 120 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 30 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 32 | ||||
-rw-r--r-- | lib/Parse/ParseInit.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 83 | ||||
-rw-r--r-- | lib/Parse/ParseOpenMP.cpp | 118 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.cpp | 140 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.h | 23 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 410 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 143 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 43 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 24 |
16 files changed, 1329 insertions, 258 deletions
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt index 55e2aebca8..01c0694d03 100644 --- a/lib/Parse/CMakeLists.txt +++ b/lib/Parse/CMakeLists.txt @@ -7,6 +7,7 @@ add_clang_library(clangParse ParseExprCXX.cpp ParseInit.cpp ParseObjc.cpp + ParseOpenMP.cpp ParsePragma.cpp ParseStmt.cpp ParseTemplate.cpp @@ -16,6 +17,7 @@ add_clang_library(clangParse add_dependencies(clangParse ClangAttrClasses + ClangAttrExprArgs ClangAttrLateParsed ClangAttrList ClangAttrParsedAttrList diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp index 5e769c5691..7cd8a21ac4 100644 --- a/lib/Parse/ParseAST.cpp +++ b/lib/Parse/ParseAST.cpp @@ -55,10 +55,21 @@ void PrettyStackTraceParserEntry::print(raw_ostream &OS) const { const Preprocessor &PP = P.getPreprocessor(); Tok.getLocation().print(OS, PP.getSourceManager()); - if (Tok.isAnnotation()) - OS << ": at annotation token \n"; - else - OS << ": current parser token '" << PP.getSpelling(Tok) << "'\n"; + if (Tok.isAnnotation()) { + OS << ": at annotation token\n"; + } else { + // Do the equivalent of PP.getSpelling(Tok) except for the parts that would + // allocate memory. + bool Invalid = false; + const SourceManager &SM = P.getPreprocessor().getSourceManager(); + unsigned Length = Tok.getLength(); + const char *Spelling = SM.getCharacterData(Tok.getLocation(), &Invalid); + if (Invalid) { + OS << ": unknown current parser token\n"; + return; + } + OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n"; + } } } // namespace diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index e15ab0ae98..5fc4189742 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -19,6 +19,13 @@ #include "clang/Sema/Scope.h" using namespace clang; +/// Get the FunctionDecl for a function or function template decl. +static FunctionDecl *getFunctionDecl(Decl *D) { + if (FunctionDecl *fn = dyn_cast<FunctionDecl>(D)) + return fn; + return cast<FunctionTemplateDecl>(D)->getTemplatedDecl(); +} + /// ParseCXXInlineMethodDef - We parsed and verified that the specified /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. @@ -50,8 +57,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, if (FnD) { Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, false, true); - bool TypeSpecContainsAuto - = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + bool TypeSpecContainsAuto = D.getDeclSpec().containsPlaceholderType(); if (Init.isUsable()) Actions.AddInitializerToDecl(FnD, Init.get(), false, TypeSpecContainsAuto); @@ -117,11 +123,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, if (FnD) { LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(FnD); - FunctionDecl *FD = 0; - if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(FnD)) - FD = FunTmpl->getTemplatedDecl(); - else - FD = cast<FunctionDecl>(FnD); + FunctionDecl *FD = getFunctionDecl(FnD); Actions.CheckForFunctionRedefinition(FD); LateParsedTemplateMap[FD] = LPT; @@ -176,6 +178,19 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, getCurrentClass().LateParsedDeclarations.pop_back(); } + // If this is a friend function, mark that it's late-parsed so that + // it's still known to be a definition even before we attach the + // parsed body. Sema needs to treat friend function definitions + // differently during template instantiation, and it's possible for + // the containing class to be instantiated before all its member + // function definitions are parsed. + // + // If you remove this, you can remove the code that clears the flag + // after parsing the member. + if (D.getDeclSpec().isFriendSpecified()) { + getFunctionDecl(FnD)->setLateTemplateParsed(true); + } + return FnD; } @@ -263,8 +278,11 @@ void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() { void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); - if (HasTemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (HasTemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); + ++CurTemplateDepthTracker; + } // The current scope is still active if we're the top-level class. // Otherwise we'll need to push and enter a new scope. @@ -285,9 +303,11 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // If this is a member template, introduce the template parameter scope. ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); - if (LM.TemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (LM.TemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method); - + ++CurTemplateDepthTracker; + } // Start the delayed C++ method declaration Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method); @@ -363,9 +383,11 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { void Parser::ParseLexedMethodDefs(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); - if (HasTemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (HasTemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); - + ++CurTemplateDepthTracker; + } bool HasClassScope = !Class.TopLevelClass; ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope); @@ -378,9 +400,11 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { void Parser::ParseLexedMethodDef(LexedMethod &LM) { // If this is a member template, introduce the template parameter scope. ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); - if (LM.TemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (LM.TemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), LM.D); - + ++CurTemplateDepthTracker; + } // Save the current token position. SourceLocation origLoc = Tok.getLocation(); @@ -391,7 +415,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); // Consume the previously pushed token. - ConsumeAnyToken(); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && "Inline method not starting with '{', ':' or 'try'"); @@ -425,8 +449,18 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { } else Actions.ActOnDefaultCtorInitializers(LM.D); + assert((Actions.getDiagnostics().hasErrorOccurred() || + !isa<FunctionTemplateDecl>(LM.D) || + cast<FunctionTemplateDecl>(LM.D)->getTemplateParameters()->getDepth() + < TemplateParameterDepth) && + "TemplateParameterDepth should be greater than the depth of " + "current template being instantiated!"); + ParseFunctionStatementBody(LM.D, FnScope); + // Clear the late-template-parsed bit if we set it before. + if (LM.D) getFunctionDecl(LM.D)->setLateTemplateParsed(false); + if (Tok.getLocation() != origLoc) { // Due to parsing error, we either went over the cached tokens or // there are still cached tokens left. If it's the latter case skip the @@ -447,9 +481,11 @@ void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); - if (HasTemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (HasTemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); - + ++CurTemplateDepthTracker; + } // Set or update the scope flags. bool AlreadyHasClassScope = Class.TopLevelClass; unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope; @@ -491,7 +527,7 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false); // Consume the previously pushed token. - ConsumeAnyToken(); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); SourceLocation EqualLoc; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 5202e694d8..6a87b78879 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 @@ -931,7 +1044,7 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, LA.Toks.push_back(Tok); PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false); // Consume the previously pushed token. - ConsumeAnyToken(); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); if (OnDefinition && !IsThreadSafetyAttribute(LA.AttrName.getName())) { // FIXME: Do not warn on C++11 attributes, once we start supporting @@ -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 @@ -2905,8 +3044,17 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; case tok::kw__Atomic: - ParseAtomicSpecifier(DS); - continue; + // C11 6.7.2.4/4: + // If the _Atomic keyword is immediately followed by a left parenthesis, + // it is interpreted as a type specifier (with a type name), not as a + // type qualifier. + if (NextToken().is(tok::l_paren)) { + ParseAtomicSpecifier(DS); + continue; + } + isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID, + getLangOpts()); + break; // OpenCL qualifiers: case tok::kw_private: @@ -3057,6 +3205,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, unsigned TagType, Decl *TagDecl) { PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc, "parsing struct/union body"); + assert(!getLangOpts().CPlusPlus && "C++ declarations not supported"); BalancedDelimiterTracker T(*this, tok::l_brace); if (T.consumeOpen()) @@ -3065,9 +3214,8 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); - // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in - // C++. - if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) { + // Empty structs are an extension in C (C99 6.7.2.1p7). + if (Tok.is(tok::r_brace)) { Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union); Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union); } @@ -3084,6 +3232,23 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, continue; } + // Parse _Static_assert declaration. + if (Tok.is(tok::kw__Static_assert)) { + SourceLocation DeclEnd; + ParseStaticAssertDeclaration(DeclEnd); + 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; @@ -3211,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(); @@ -3253,7 +3418,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType); if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), - /*EnteringContext=*/false)) + /*EnteringContext=*/true)) return; if (SS.isSet() && Tok.isNot(tok::identifier)) { @@ -3598,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(); @@ -3814,7 +3979,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw_private: return getLangOpts().OpenCL; - // C11 _Atomic() + // C11 _Atomic case tok::kw__Atomic: return true; } @@ -3878,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__: @@ -3959,7 +4126,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::annot_decltype: case tok::kw_constexpr: - // C11 _Atomic() + // C11 _Atomic case tok::kw__Atomic: return true; @@ -4099,7 +4266,8 @@ bool Parser::isConstructorDeclarator() { /// void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool VendorAttributesAllowed, - bool CXX11AttributesAllowed) { + bool CXX11AttributesAllowed, + bool AtomicAllowed) { if (getLangOpts().CPlusPlus11 && CXX11AttributesAllowed && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); @@ -4132,6 +4300,12 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, getLangOpts()); break; + case tok::kw__Atomic: + if (!AtomicAllowed) + goto DoneWithTypeQuals; + isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID, + getLangOpts()); + break; // OpenCL qualifiers: case tok::kw_private: @@ -4346,6 +4520,10 @@ void Parser::ParseDeclaratorInternal(Declarator &D, if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) Diag(DS.getVolatileSpecLoc(), diag::err_invalid_reference_qualifier_application) << "volatile"; + // 'restrict' is permitted as an extension. + if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) + Diag(DS.getAtomicSpecLoc(), + diag::err_invalid_reference_qualifier_application) << "_Atomic"; } // Recursively parse the declarator. @@ -4368,7 +4546,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, } } - // Remember that we parsed a reference type. It doesn't have type-quals. + // Remember that we parsed a reference type. D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc, Kind == tok::amp), DS.getAttributes(), @@ -4809,7 +4987,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D, // with the virt-specifier-seq and pure-specifier in the same way. // Parse cv-qualifier-seq[opt]. - ParseTypeQualifierListOpt(DS, false /*no attributes*/, false); + ParseTypeQualifierListOpt(DS, /*VendorAttributesAllowed*/ false, + /*CXX11AttributesAllowed*/ false, + /*AtomicAllowed*/ false); if (!DS.getSourceRange().getEnd().isInvalid()) { EndLoc = DS.getSourceRange().getEnd(); ConstQualifierLoc = DS.getConstSpecLoc(); @@ -4833,16 +5013,19 @@ void Parser::ParseFunctionDeclarator(Declarator &D, // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq // and the end of the function-definition, member-declarator, or // declarator. + // FIXME: currently, "static" case isn't handled correctly. bool IsCXX11MemberFunction = getLangOpts().CPlusPlus11 && - (D.getContext() == Declarator::MemberContext || - (D.getContext() == Declarator::FileContext && - D.getCXXScopeSpec().isValid() && - Actions.CurContext->isRecord())); + (D.getContext() == Declarator::MemberContext + ? !D.getDeclSpec().isFriendSpecified() + : D.getContext() == Declarator::FileContext && + D.getCXXScopeSpec().isValid() && + Actions.CurContext->isRecord()); Sema::CXXThisScopeRAII ThisScope(Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), DS.getTypeQualifiers() | - (D.getDeclSpec().isConstexprSpecified() + (D.getDeclSpec().isConstexprSpecified() && + !getLangOpts().CPlusPlus1y ? Qualifiers::Const : 0), IsCXX11MemberFunction); @@ -5348,14 +5531,13 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { /// _Atomic ( type-name ) /// void Parser::ParseAtomicSpecifier(DeclSpec &DS) { - assert(Tok.is(tok::kw__Atomic) && "Not an atomic specifier"); + assert(Tok.is(tok::kw__Atomic) && NextToken().is(tok::l_paren) && + "Not an atomic specifier"); SourceLocation StartLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, "_Atomic")) { - SkipUntil(tok::r_paren); + if (T.consumeOpen()) return; - } TypeResult Result = ParseTypeName(); if (Result.isInvalid()) { diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index f040b9bfff..f1fbbb15fe 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -468,7 +468,10 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, } // Parse nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + IdentifierInfo *LastII = 0; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false, + /*MayBePseudoDtor=*/0, /*IsTypename=*/false, + /*LastII=*/&LastII); // Check nested-name specifier. if (SS.isInvalid()) { @@ -476,18 +479,31 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } + SourceLocation TemplateKWLoc; + UnqualifiedId Name; + // Parse the unqualified-id. We allow parsing of both constructor and // destructor names and allow the action module to diagnose any semantic // errors. - SourceLocation TemplateKWLoc; - UnqualifiedId Name; - if (ParseUnqualifiedId(SS, - /*EnteringContext=*/false, - /*AllowDestructorName=*/true, - /*AllowConstructorName=*/true, - ParsedType(), |