diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:18:08 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:18:08 +0000 |
commit | bab175ec4b075c8076ba14c762900392533f6ee4 (patch) | |
tree | 01f4f29419a2cb10abe13c1e63cd2a66068b0137 /lib/Parse | |
parent | 8b7a8012d223fac5d17d16a66bb39168a9a1dfc0 (diff) | |
download | src-bab175ec4b075c8076ba14c762900392533f6ee4.tar.gz src-bab175ec4b075c8076ba14c762900392533f6ee4.zip |
Vendor import of clang trunk r290819:vendor/clang/clang-trunk-r290819
Notes
Notes:
svn path=/vendor/clang/dist/; revision=311118
svn path=/vendor/clang/clang-trunk-r290819/; revision=311119; tag=vendor/clang/clang-trunk-r290819
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/ParseAST.cpp | 22 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 52 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 211 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 539 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 19 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 168 | ||||
-rw-r--r-- | lib/Parse/ParseInit.cpp | 3 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 47 | ||||
-rw-r--r-- | lib/Parse/ParseOpenMP.cpp | 58 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.cpp | 201 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 10 | ||||
-rw-r--r-- | lib/Parse/ParseStmtAsm.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 12 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 13 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 219 |
15 files changed, 1156 insertions, 424 deletions
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp index 1fb57a08c433..d018d4c08ed9 100644 --- a/lib/Parse/ParseAST.cpp +++ b/lib/Parse/ParseAST.cpp @@ -138,26 +138,18 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { S.getPreprocessor().EnterMainSourceFile(); P.Initialize(); - // C11 6.9p1 says translation units must have at least one top-level - // declaration. C++ doesn't have this restriction. We also don't want to - // complain if we have a precompiled header, although technically if the PCH - // is empty we should still emit the (pedantic) diagnostic. Parser::DeclGroupPtrTy ADecl; ExternalASTSource *External = S.getASTContext().getExternalSource(); if (External) External->StartTranslationUnit(Consumer); - if (P.ParseTopLevelDecl(ADecl)) { - if (!External && !S.getLangOpts().CPlusPlus) - P.Diag(diag::ext_empty_translation_unit); - } else { - do { - // If we got a null return and something *was* parsed, ignore it. This - // is due to a top-level semicolon, an action override, or a parse error - // skipping something. - if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) - return; - } while (!P.ParseTopLevelDecl(ADecl)); + for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF; + AtEOF = P.ParseTopLevelDecl(ADecl)) { + // If we got a null return and something *was* parsed, ignore it. This + // is due to a top-level semicolon, an action override, or a parse error + // skipping something. + if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) + return; } // Process any TopLevelDecls generated by #pragma weak. diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 39fcc8270419..c52b61e7e983 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -319,7 +319,8 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // Introduce the parameter into scope. bool HasUnparsed = Param->hasUnparsedDefaultArg(); Actions.ActOnDelayedCXXMethodParameter(getCurScope(), Param); - if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { + std::unique_ptr<CachedTokens> Toks = std::move(LM.DefaultArgs[I].Toks); + if (Toks) { // Mark the end of the default argument so that we know when to stop when // we parse it later on. Token LastDefaultArgToken = Toks->back(); @@ -377,9 +378,6 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { if (Tok.is(tok::eof) && Tok.getEofData() == Param) ConsumeAnyToken(); - - delete Toks; - LM.DefaultArgs[I].Toks = nullptr; } else if (HasUnparsed) { assert(Param->hasInheritedDefaultArg()); FunctionDecl *Old = cast<FunctionDecl>(LM.Method)->getPreviousDecl(); @@ -832,22 +830,30 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { } } - if (Tok.isOneOf(tok::identifier, tok::kw_template)) { + if (Tok.is(tok::identifier)) { Toks.push_back(Tok); ConsumeToken(); - } else if (Tok.is(tok::code_completion)) { - Toks.push_back(Tok); - ConsumeCodeCompletionToken(); - // Consume the rest of the initializers permissively. - // FIXME: We should be able to perform code-completion here even if - // there isn't a subsequent '{' token. - MightBeTemplateArgument = true; - break; } else { break; } } while (Tok.is(tok::coloncolon)); + if (Tok.is(tok::code_completion)) { + Toks.push_back(Tok); + ConsumeCodeCompletionToken(); + if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_decltype)) { + // Could be the start of another member initializer (the ',' has not + // been written yet) + continue; + } + } + + if (Tok.is(tok::comma)) { + // The initialization is missing, we'll diagnose it later. + Toks.push_back(Tok); + ConsumeToken(); + continue; + } if (Tok.is(tok::less)) MightBeTemplateArgument = true; @@ -888,6 +894,26 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { // means the initializer is malformed; we'll diagnose it later. if (!getLangOpts().CPlusPlus11) return false; + + const Token &PreviousToken = Toks[Toks.size() - 2]; + if (!MightBeTemplateArgument && + !PreviousToken.isOneOf(tok::identifier, tok::greater, + tok::greatergreater)) { + // If the opening brace is not preceded by one of these tokens, we are + // missing the mem-initializer-id. In order to recover better, we need + // to use heuristics to determine if this '{' is most likely the + // begining of a brace-init-list or the function body. + // Check the token after the corresponding '}'. + TentativeParsingAction PA(*this); + if (SkipUntil(tok::r_brace) && + !Tok.isOneOf(tok::comma, tok::ellipsis, tok::l_brace)) { + // Consider there was a malformed initializer and this is the start + // of the function body. We'll diagnose it later. + PA.Revert(); + return false; + } + PA.Revert(); + } } // Grab the initializer (or the subexpression of the template argument). diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 45e1c3e465ce..ad4005747310 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -25,6 +25,7 @@ #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaDiagnostic.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" @@ -301,10 +302,10 @@ unsigned Parser::ParseAttributeArgsCommon( // Parse the non-empty comma-separated list of expressions. do { - std::unique_ptr<EnterExpressionEvaluationContext> Unevaluated; - if (attributeParsedArgsUnevaluated(*AttrName)) - Unevaluated.reset( - new EnterExpressionEvaluationContext(Actions, Sema::Unevaluated)); + bool ShouldEnter = attributeParsedArgsUnevaluated(*AttrName); + EnterExpressionEvaluationContext Unevaluated( + Actions, Sema::Unevaluated, /*LambdaContextDecl=*/nullptr, + /*IsDecltype=*/false, ShouldEnter); ExprResult ArgExpr( Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); @@ -366,13 +367,13 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, // These may refer to the function arguments, but need to be parsed early to // participate in determining whether it's a redeclaration. - std::unique_ptr<ParseScope> PrototypeScope; + llvm::Optional<ParseScope> PrototypeScope; if (normalizeAttrName(AttrName->getName()) == "enable_if" && D && D->isFunctionDeclarator()) { DeclaratorChunk::FunctionTypeInfo FTI = D->getFunctionTypeInfo(); - PrototypeScope.reset(new ParseScope(this, Scope::FunctionPrototypeScope | - Scope::FunctionDeclarationScope | - Scope::DeclScope)); + PrototypeScope.emplace(this, Scope::FunctionPrototypeScope | + Scope::FunctionDeclarationScope | + Scope::DeclScope); for (unsigned i = 0; i != FTI.NumParams; ++i) { ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param); Actions.ActOnReenterCXXMethodParameter(getCurScope(), Param); @@ -605,6 +606,7 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { case tok::kw___fastcall: case tok::kw___stdcall: case tok::kw___thiscall: + case tok::kw___regcall: case tok::kw___cdecl: case tok::kw___vectorcall: case tok::kw___ptr64: @@ -1407,39 +1409,53 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { << attrs.Range; } -void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs) { - AttributeList *AttrList = attrs.getList(); - while (AttrList) { - if (AttrList->isCXX11Attribute()) { - Diag(AttrList->getLoc(), diag::err_attribute_not_type_attr) - << AttrList->getName(); - AttrList->setInvalid(); +void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs, + unsigned DiagID) { + for (AttributeList *Attr = Attrs.getList(); Attr; Attr = Attr->getNext()) { + if (!Attr->isCXX11Attribute()) + continue; + if (Attr->getKind() == AttributeList::UnknownAttribute) + Diag(Attr->getLoc(), diag::warn_unknown_attribute_ignored) + << Attr->getName(); + else { + Diag(Attr->getLoc(), DiagID) + << Attr->getName(); + Attr->setInvalid(); } - AttrList = AttrList->getNext(); } } +// Usually, `__attribute__((attrib)) class Foo {} var` means that attribute +// applies to var, not the type Foo. // As an exception to the rule, __declspec(align(...)) before the // class-key affects the type instead of the variable. -void Parser::handleDeclspecAlignBeforeClassKey(ParsedAttributesWithRange &Attrs, - DeclSpec &DS, - Sema::TagUseKind TUK) { +// Also, Microsoft-style [attributes] seem to affect the type instead of the +// variable. +// This function moves attributes that should apply to the type off DS to Attrs. +void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributesWithRange &Attrs, + DeclSpec &DS, + Sema::TagUseKind TUK) { if (TUK == Sema::TUK_Reference) return; ParsedAttributes &PA = DS.getAttributes(); AttributeList *AL = PA.getList(); AttributeList *Prev = nullptr; + AttributeList *TypeAttrHead = nullptr; + AttributeList *TypeAttrTail = nullptr; while (AL) { AttributeList *Next = AL->getNext(); - // We only consider attributes using the appropriate '__declspec' spelling. - // This behavior doesn't extend to any other spellings. - if (AL->getKind() == AttributeList::AT_Aligned && - AL->isDeclspecAttribute()) { + if ((AL->getKind() == AttributeList::AT_Aligned && + AL->isDeclspecAttribute()) || + AL->isMicrosoftAttribute()) { // Stitch the attribute into the tag's attribute list. - AL->setNext(nullptr); - Attrs.add(AL); + if (TypeAttrTail) + TypeAttrTail->setNext(AL); + else + TypeAttrHead = AL; + TypeAttrTail = AL; + TypeAttrTail->setNext(nullptr); // Remove the attribute from the variable's attribute list. if (Prev) { @@ -1457,6 +1473,12 @@ void Parser::handleDeclspecAlignBeforeClassKey(ParsedAttributesWithRange &Attrs, AL = Next; } + + // Find end of type attributes Attrs and add NewTypeAttributes in the same + // order they were in originally. (Remember, in AttributeList things earlier + // in source order are later in the list, since new attributes are added to + // the front of the list.) + Attrs.addAllAtEnd(TypeAttrHead); } /// ParseDeclaration - Parse a full 'declaration', which consists of @@ -1484,7 +1506,6 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, ObjCDeclContextSwitch ObjCDC(*this); Decl *SingleDecl = nullptr; - Decl *OwnedType = nullptr; switch (Tok.getKind()) { case tok::kw_template: case tok::kw_export: @@ -1504,9 +1525,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, ProhibitAttributes(attrs); return ParseNamespace(Context, DeclEnd); case tok::kw_using: - SingleDecl = ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(), - DeclEnd, attrs, &OwnedType); - break; + return ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(), + DeclEnd, attrs); case tok::kw_static_assert: case tok::kw__Static_assert: ProhibitAttributes(attrs); @@ -1517,9 +1537,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, } // This routine returns a DeclGroup, if the thing we parsed only contains a - // single decl, convert it now. Alias declarations can also declare a type; - // include that too if it is present. - return Actions.ConvertDeclToDeclGroup(SingleDecl, OwnedType); + // single decl, convert it now. + return Actions.ConvertDeclToDeclGroup(SingleDecl); } /// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl] @@ -2717,7 +2736,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Reject C++11 attributes that appertain to decl specifiers as // we don't support any C++11 attributes that appertain to decl // specifiers. This also conforms to what g++ 4.8 is doing. - ProhibitCXX11Attributes(attrs); + ProhibitCXX11Attributes(attrs, diag::err_attribute_not_type_attr); DS.takeAttributesFrom(attrs); } @@ -3117,6 +3136,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: + case tok::kw___regcall: case tok::kw___vectorcall: ParseMicrosoftTypeAttributes(DS.getAttributes()); continue; @@ -4067,7 +4087,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } - handleDeclspecAlignBeforeClassKey(attrs, DS, TUK); + stripTypeAttributesOffDeclSpec(attrs, DS, TUK); Sema::SkipBodyInfo SkipBody; if (!Name && TUK == Sema::TUK_Definition && Tok.is(tok::l_brace) && @@ -4169,7 +4189,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { // C does not allow an empty enumerator-list, C++ does [dcl.enum]. if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) - Diag(Tok, diag::error_empty_enum); + Diag(Tok, diag::err_empty_enum); SmallVector<Decl *, 32> EnumConstantDecls; SmallVector<SuppressAccessChecks, 32> EnumAvailabilityDiags; @@ -4224,7 +4244,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { if (Tok.is(tok::identifier)) { // We're missing a comma between enumerators. - SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation); + SourceLocation Loc = getEndOfPreviousToken(); Diag(Loc, diag::err_enumerator_list_missing_comma) << FixItHint::CreateInsertion(Loc, ", "); continue; @@ -4434,6 +4454,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: + case tok::kw___regcall: case tok::kw___vectorcall: case tok::kw___w64: case tok::kw___ptr64: @@ -4618,6 +4639,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: + case tok::kw___regcall: case tok::kw___vectorcall: case tok::kw___w64: case tok::kw___sptr: @@ -4856,6 +4878,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs, case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: + case tok::kw___regcall: case tok::kw___vectorcall: if (AttrReqs & AR_DeclspecAttributesParsed) { ParseMicrosoftTypeAttributes(DS.getAttributes()); @@ -5200,12 +5223,22 @@ static SourceLocation getMissingDeclaratorIdLoc(Declarator &D, /// '~' class-name /// template-id /// +/// C++17 adds the following, which we also handle here: +/// +/// simple-declaration: +/// <decl-spec> '[' identifier-list ']' brace-or-equal-initializer ';' +/// /// Note, any additional constructs added here may need corresponding changes /// in isConstructorDeclarator. void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) { + // This might be a C++17 structured binding. + if (Tok.is(tok::l_square) && !D.mayOmitIdentifier() && + D.getCXXScopeSpec().isEmpty()) + return ParseDecompositionDeclarator(D); + // Don't parse FOO:BAR as if it were a typo for FOO::BAR inside a class, in // this context it is a bitfield. Also in range-based for statement colon // may delimit for-range-declaration. @@ -5228,6 +5261,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // Change the declaration context for name lookup, until this function // is exited (and the declarator has been parsed). DeclScopeObj.EnterDeclaratorScope(); + else if (getObjCDeclContext()) { + // Ensure that we don't interpret the next token as an identifier when + // dealing with declarations in an Objective-C container. + D.SetIdentifier(nullptr, Tok.getLocation()); + D.setInvalidType(true); + ConsumeToken(); + goto PastIdentifier; + } } // C++0x [dcl.fct]p14: @@ -5435,6 +5476,70 @@ void Parser::ParseDirectDeclarator(Declarator &D) { } } +void Parser::ParseDecompositionDeclarator(Declarator &D) { + assert(Tok.is(tok::l_square)); + + // If this doesn't look like a structured binding, maybe it's a misplaced + // array declarator. + // FIXME: Consume the l_square first so we don't need extra lookahead for + // this. + if (!(NextToken().is(tok::identifier) && + GetLookAheadToken(2).isOneOf(tok::comma, tok::r_square)) && + !(NextToken().is(tok::r_square) && + GetLookAheadToken(2).isOneOf(tok::equal, tok::l_brace))) + return ParseMisplacedBracketDeclarator(D); + + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + + SmallVector<DecompositionDeclarator::Binding, 32> Bindings; + while (Tok.isNot(tok::r_square)) { + if (!Bindings.empty()) { + if (Tok.is(tok::comma)) + ConsumeToken(); + else { + if (Tok.is(tok::identifier)) { + SourceLocation EndLoc = getEndOfPreviousToken(); + Diag(EndLoc, diag::err_expected) + << tok::comma << FixItHint::CreateInsertion(EndLoc, ","); + } else { + Diag(Tok, diag::err_expected_comma_or_rsquare); + } + + SkipUntil(tok::r_square, tok::comma, tok::identifier, + StopAtSemi | StopBeforeMatch); + if (Tok.is(tok::comma)) + ConsumeToken(); + else if (Tok.isNot(tok::identifier)) + break; + } + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected) << tok::identifier; + break; + } + + Bindings.push_back({Tok.getIdentifierInfo(), Tok.getLocation()}); + ConsumeToken(); + } + + if (Tok.isNot(tok::r_square)) + // We've already diagnosed a problem here. + T.skipToEnd(); + else { + // C++17 does not allow the identifier-list in a structured binding + // to be empty. + if (Bindings.empty()) + Diag(Tok.getLocation(), diag::ext_decomp_decl_empty); + + T.consumeClose(); + } + + return D.setDecompositionBindings(T.getOpenLocation(), Bindings, + T.getCloseLocation()); +} + /// ParseParenDeclarator - We parsed the declarator D up to a paren. This is /// only called before the identifier, so these are most likely just grouping /// parens for precedence. If we find that these are actually function @@ -5719,6 +5824,21 @@ void Parser::ParseFunctionDeclarator(Declarator &D, } } + // Collect non-parameter declarations from the prototype if this is a function + // declaration. They will be moved into the scope of the function. Only do + // this in C and not C++, where the decls will continue to live in the + // surrounding context. + SmallVector<NamedDecl *, 0> DeclsInPrototype; + if (getCurScope()->getFlags() & Scope::FunctionDeclarationScope && + !getLangOpts().CPlusPlus) { + for (Decl *D : getCurScope()->decls()) { + NamedDecl *ND = dyn_cast<NamedDecl>(D); + if (!ND || isa<ParmVarDecl>(ND)) + continue; + DeclsInPrototype.push_back(ND); + } + } + // Remember that we parsed a function type, and remember the attributes. D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto, IsAmbiguous, @@ -5738,6 +5858,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, ExceptionSpecTokens, + DeclsInPrototype, StartLoc, LocalEndLoc, D, TrailingReturnType), FnAttrs, EndLoc); @@ -5783,7 +5904,8 @@ bool Parser::isFunctionDeclaratorIdentifierList() { // To handle this, we check to see if the token after the first // identifier is a "," or ")". Only then do we parse it as an // identifier list. - && (NextToken().is(tok::comma) || NextToken().is(tok::r_paren)); + && (!Tok.is(tok::eof) && + (NextToken().is(tok::comma) || NextToken().is(tok::r_paren))); } /// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator @@ -5921,7 +6043,7 @@ void Parser::ParseParameterDeclarationClause( // DefArgToks is used when the parsing of default arguments needs // to be delayed. - CachedTokens *DefArgToks = nullptr; + std::unique_ptr<CachedTokens> DefArgToks; // If no parameter was specified, verify that *something* was specified, // otherwise we have a missing type and identifier. @@ -5957,13 +6079,11 @@ void Parser::ParseParameterDeclarationClause( // If we're inside a class definition, cache the tokens // corresponding to the default argument. We'll actually parse // them when we see the end of the class definition. - // FIXME: Can we use a smart pointer for Toks? - DefArgToks = new CachedTokens; + DefArgToks.reset(new CachedTokens); SourceLocation ArgStartLoc = NextToken().getLocation(); if (!ConsumeAndStoreInitializer(*DefArgToks, CIK_DefaultArgument)) { - delete DefArgToks; - DefArgToks = nullptr; + DefArgToks.reset(); Actions.ActOnParamDefaultArgumentError(Param, EqualLoc); } else { Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc, @@ -5999,7 +6119,7 @@ void Parser::ParseParameterDeclarationClause( ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, ParmDeclarator.getIdentifierLoc(), - Param, DefArgToks)); + Param, std::move(DefArgToks))); } if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) { @@ -6149,8 +6269,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { T.consumeClose(); - ParsedAttributes attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(DS.getAttributes()); // Remember that we parsed a array type, and remember its features. D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), @@ -6158,7 +6277,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { NumElements.get(), T.getOpenLocation(), T.getCloseLocation()), - attrs, T.getCloseLocation()); + DS.getAttributes(), T.getCloseLocation()); } /// Diagnose brackets before an identifier. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 6436e3dfc763..4002b09d2bc4 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -217,7 +217,6 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation> &IdentLoc, Tok.isNot(tok::eof)) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); - MaybeParseMicrosoftAttributes(attrs); ParseExternalDeclaration(attrs); } @@ -310,7 +309,6 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); - MaybeParseMicrosoftAttributes(attrs); if (Tok.isNot(tok::l_brace)) { // Reset the source range in DS, as the leading "extern" @@ -361,7 +359,6 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { default: ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); - MaybeParseMicrosoftAttributes(attrs); ParseExternalDeclaration(attrs); continue; } @@ -375,13 +372,60 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { : nullptr; } +/// Parse a C++ Modules TS export-declaration. +/// +/// export-declaration: +/// 'export' declaration +/// 'export' '{' declaration-seq[opt] '}' +/// +Decl *Parser::ParseExportDeclaration() { + assert(Tok.is(tok::kw_export)); + SourceLocation ExportLoc = ConsumeToken(); + + ParseScope ExportScope(this, Scope::DeclScope); + Decl *ExportDecl = Actions.ActOnStartExportDecl( + getCurScope(), ExportLoc, + Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation()); + + if (Tok.isNot(tok::l_brace)) { + // FIXME: Factor out a ParseExternalDeclarationWithAttrs. + ParsedAttributesWithRange Attrs(AttrFactory); + MaybeParseCXX11Attributes(Attrs); + MaybeParseMicrosoftAttributes(Attrs); + ParseExternalDeclaration(Attrs); + return Actions.ActOnFinishExportDecl(getCurScope(), ExportDecl, + SourceLocation()); + } + + BalancedDelimiterTracker T(*this, tok::l_brace); + T.consumeOpen(); + + // The Modules TS draft says "An export-declaration shall declare at least one + // entity", but the intent is that it shall contain at least one declaration. + if (Tok.is(tok::r_brace)) + Diag(ExportLoc, diag::err_export_empty) + << SourceRange(ExportLoc, Tok.getLocation()); + + while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) && + Tok.isNot(tok::eof)) { + ParsedAttributesWithRange Attrs(AttrFactory); + MaybeParseCXX11Attributes(Attrs); + MaybeParseMicrosoftAttributes(Attrs); + ParseExternalDeclaration(Attrs); + } + + T.consumeClose(); + return Actions.ActOnFinishExportDecl(getCurScope(), ExportDecl, + T.getCloseLocation()); +} + /// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or /// using-directive. Assumes that current token is 'using'. -Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, +Parser::DeclGroupPtrTy +Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, const ParsedTemplateInfo &TemplateInfo, - SourceLocation &DeclEnd, - ParsedAttributesWithRange &attrs, - Decl **OwnedType) { + SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs) { assert(Tok.is(tok::kw_using) && "Not using token"); ObjCDeclContextSwitch ObjCDC(*this); @@ -403,7 +447,8 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, << 0 /* directive */ << R << FixItHint::CreateRemoval(R); } - return ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs); + Decl *UsingDir = ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs); + return Actions.ConvertDeclToDeclGroup(UsingDir); } // Otherwise, it must be a using-declaration or an alias-declaration. @@ -412,7 +457,7 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, ProhibitAttributes(attrs); return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd, - AS_none, OwnedType); + AS_none); } /// ParseUsingDirective - Parse C++ using-directive, assumes @@ -478,58 +523,31 @@ Decl *Parser::ParseUsingDirective(unsigned Context, IdentLoc, NamespcName, attrs.getList()); } -/// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration. -/// Assumes that 'using' was already seen. -/// -/// using-declaration: [C++ 7.3.p3: namespace.udecl] -/// 'using' 'typename'[opt] ::[opt] nested-name-specifier -/// unqualified-id -/// 'using' :: unqualified-id +/// Parse a using-declarator (or the identifier in a C++11 alias-declaration). /// -/// alias-declaration: C++11 [dcl.dcl]p1 -/// 'using' identifier attribute-specifier-seq[opt] = type-id ; +/// using-declarator: +/// 'typename'[opt] nested-name-specifier unqualified-id /// -Decl *Parser::ParseUsingDeclaration(unsigned Context, - const ParsedTemplateInfo &TemplateInfo, - SourceLocation UsingLoc, - SourceLocation &DeclEnd, - AccessSpecifier AS, - Decl **OwnedType) { - CXXScopeSpec SS; - SourceLocation TypenameLoc; - bool HasTypenameKeyword = false; - - // Check for misplaced attributes before the identifier in an - // alias-declaration. - ParsedAttributesWithRange MisplacedAttrs(AttrFactory); - MaybeParseCXX11Attributes(MisplacedAttrs); +bool Parser::ParseUsingDeclarator(unsigned Context, UsingDeclarator &D) { + D.clear(); // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. - if (TryConsumeToken(tok::kw_typename, TypenameLoc)) - HasTypenameKeyword = true; + TryConsumeToken(tok::kw_typename, D.TypenameLoc); if (Tok.is(tok::kw___super)) { Diag(Tok.getLocation(), diag::err_super_in_using_declaration); - SkipUntil(tok::semi); - return nullptr; + return true; } // Parse nested-name-specifier. IdentifierInfo *LastII = nullptr; - ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false, + ParseOptionalCXXScopeSpecifier(D.SS, nullptr, /*EnteringContext=*/false, /*MayBePseudoDtor=*/nullptr, /*IsTypename=*/false, /*LastII=*/&LastII); - - // Check nested-name specifier. - if (SS.isInvalid()) { - SkipUntil(tok::semi); - return nullptr; - } - - SourceLocation TemplateKWLoc; - UnqualifiedId Name; + if (D.SS.isInvalid()) + return true; // Parse the unqualified-id. We allow parsing of both constructor and // destructor names and allow the action module to diagnose any semantic @@ -542,32 +560,74 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, // nested-name-specifier, the name is [...] considered to name the // constructor. if (getLangOpts().CPlusPlus11 && Context == Declarator::MemberContext && - Tok.is(tok::identifier) && NextToken().is(tok::semi) && - SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() && - !SS.getScopeRep()->getAsNamespace() && - !SS.getScopeRep()->getAsNamespaceAlias()) { + Tok.is(tok::identifier) && + (NextToken().is(tok::semi) || NextToken().is(tok::comma) || + NextToken().is(tok::ellipsis)) && + D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() && + !D.SS.getScopeRep()->getAsNamespace() && + !D.SS.getScopeRep()->getAsNamespaceAlias()) { SourceLocation IdLoc = ConsumeToken(); - ParsedType Type = Actions.getInheritingConstructorName(SS, IdLoc, *LastII); - Name.setConstructorName(Type, IdLoc, IdLoc); - } else if (ParseUnqualifiedId( - SS, /*EnteringContext=*/false, - /*AllowDestructorName=*/true, - /*AllowConstructorName=*/!(Tok.is(tok::identifier) && - NextToken().is(tok::equal)), - nullptr, TemplateKWLoc, Name)) { - SkipUntil(tok::semi); - return nullptr; + ParsedType Type = + Actions.getInheritingConstructorName(D.SS, IdLoc, *LastII); + D.Name.setConstructorName(Type, IdLoc, IdLoc); + } else { + if (ParseUnqualifiedId( + D.SS, /*EnteringContext=*/false, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/!(Tok.is(tok::identifier) && + NextToken().is(tok::equal)), + nullptr, D.TemplateKWLoc, D.Name)) + return true; } + if (TryConsumeToken(tok::ellipsis, D.EllipsisLoc)) + Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z ? + diag::warn_cxx1z_compat_using_declaration_pack : + diag::ext_using_declaration_pack); + + return false; +} + +/// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration. +/// Assumes that 'using' was already seen. +/// +/// using-declaration: [C++ 7.3.p3: namespace.udecl] +/// 'using' using-declarator-list[opt] ; +/// +/// using-declarator-list: [C++1z] +/// using-declarator '...'[opt] +/// using-declarator-list ',' using-declarator '...'[opt] +/// +/// using-declarator-list: [C++98-14] +/// using-declarator +/// +/// alias-declaration: C++11 [dcl.dcl]p1 +/// 'using' identifier attribute-specifier-seq[opt] = type-id ; +/// +Parser::DeclGroupPtrTy +Parser::ParseUsingDeclaration(unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + SourceLocation UsingLoc, SourceLocation &DeclEnd, + AccessSpecifier AS) { + // Check for misplaced attributes before the identifier in an + // alias-declaration. + ParsedAttributesWithRange MisplacedAttrs(AttrFactory); + MaybeParseCXX11Attributes(MisplacedAttrs); + + UsingDeclarator D; + bool InvalidDeclarator = ParseUsingDeclarator(Context, D); + ParsedAttributesWithRange Attrs(AttrFactory); MaybeParseGNUAttributes(Attrs); MaybeParseCXX11Attributes(Attrs); // Maybe this is an alias-declaration. - TypeResult TypeAlias; - bool IsAliasDecl = Tok.is(tok::equal); - Decl *DeclFromDeclSpec = nullptr; - if (IsAliasDecl) { + if (Tok.is(tok::equal)) { + if (InvalidDeclarator) { + SkipUntil(tok::semi); + return nullptr; + } + // If we had any misplaced attributes from earlier, this is where they // should have been written. if (MisplacedAttrs.Range.isValid()) { @@ -579,109 +639,156 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, Attrs.takeAllFrom(MisplacedAttrs); } - ConsumeToken(); + Decl *DeclFromDeclSpec = nullptr; + Decl *AD = ParseAliasDeclarationAfterDeclarator( + TemplateInfo, UsingLoc, D, DeclEnd, AS, Attrs, &DeclFromDeclSpec); + return Actions.ConvertDeclToDeclGroup(AD, DeclFromDeclSpec); + } - Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_alias_declaration : - diag::ext_alias_declaration); - - // Type alias templates cannot be specialized. - int SpecKind = -1; - if (TemplateInfo.Kind == ParsedTemplateInfo::Template && - Name.getKind() == UnqualifiedId::IK_TemplateId) - SpecKind = 0; - if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization) - SpecKind = 1; - if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) - SpecKind = 2; - if (SpecKind != -1) { - SourceRange Range; - if (SpecKind == 0) - Range = SourceRange(Name.TemplateId->LAngleLoc, - Name.TemplateId->RAngleLoc); - else - Range = TemplateInfo.getSourceRange(); - Diag(Range.getBegin(), diag::err_alias_declaration_specialization) - << SpecKind << Range; - SkipUntil(tok::semi); - return nullptr; - } + // C++11 attributes are not allowed on a using-declaration, but GNU ones + // are. + ProhibitAttributes(MisplacedAttrs); + ProhibitAttributes(Attrs); - // Name must be an identifier. - if (Name.getKind() != UnqualifiedId::IK_Identifier) { - Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier); - // No removal fixit: can't recover from this. - SkipUntil(tok::semi); - return nullptr; - } else if (HasTypenameKeyword) - Diag(TypenameLoc, diag::err_alias_declaration_not_identifier) - << FixItHint::CreateRemoval(SourceRange(TypenameLoc, - SS.isNotEmpty() ? SS.getEndLoc() : TypenameLoc)); - else if (SS.isNotEmpty()) - Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier) - << FixItHint::CreateRemoval(SS.getRange()); + // Diagnose an attempt to declare a templated using-declaration. + // In C++11, alias-declarations can be templates: + // template <...> using id = type; + if (TemplateInfo.Kind) { + SourceRange R = TemplateInfo.getSourceRange(); + Diag(UsingLoc, diag::err_templated_using_directive_declaration) + << 1 /* declaration */ << R << FixItHint::CreateRemoval(R); - TypeAlias = ParseTypeName(nullptr, TemplateInfo.Kind - ? Declarator::AliasTemplateContext - : Declarator::AliasDeclContext, - AS, &DeclFromDeclSpec, &Attrs); - if (OwnedType) - *OwnedType = DeclFromDeclSpec; - } else { - // C++11 attributes are not allowed on a using-declaration, but GNU ones - // are. - ProhibitAttributes(MisplacedAttrs); - ProhibitAttributes(Attrs); + // Unfortunately, we have to bail out instead of recovering by + // ignoring the parameters, just in case the nested name specifier + // depends on the parameters. + return nullptr; + } + SmallVector<Decl *, 8> DeclsInGroup; + while (true) { // Parse (optional) attributes (most likely GNU strong-using extension). MaybeParseGNUAttributes(Attrs); + + if (InvalidDeclarator) + SkipUntil(tok::comma, tok::semi, StopBeforeMatch); + else { + // "typename" keyword is allowed for identifiers only, + // because it may be a type definition. + if (D.TypenameLoc.isValid() && + D.Name.getKind() != UnqualifiedId::IK_Identifier) { + Diag(D.Name.getSourceRange().getBegin(), + diag::err_typename_identifiers_only) + << FixItHint::CreateRemoval(SourceRange(D.TypenameLoc)); + // Proceed parsing, but discard the typename keyword. + D.TypenameLoc = SourceLocation(); + } + + Decl *UD = Actions.ActOnUsingDeclaration(getCurScope(), AS, UsingLoc, + D.TypenameLoc, D.SS, D.Name, + D.EllipsisLoc, Attrs.getList()); + if (UD) + DeclsInGroup.push_back(UD); + } + + if (!TryConsumeToken(tok::comma)) + break; + + // Parse another using-declarator. + Attrs.clear(); + InvalidDeclarator = ParseUsingDeclarator(Context, D); } + if (DeclsInGroup.size() > 1) + Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z ? + diag::warn_cxx1z_compat_multi_using_declaration : + diag::ext_multi_using_declaration); + // Eat ';'. DeclEnd = Tok.getLocation(); if (ExpectAndConsume(tok::semi, diag::err_expected_after, !Attrs.empty() ? "attributes list" - : IsAliasDecl ? "alias declaration" - : "using declaration")) + : "using declaration")) SkipUntil(tok::semi); - // Diagnose an attempt to declare a templated using-declaration. - // In C++11, alias-declarations can be templates: - // template <...> using id = type; - if (TemplateInfo.Kind && !IsAliasDecl) { - SourceRange R = TemplateInfo.getSourceRange(); - Diag(UsingLoc, diag::err_templated_using_directive_declaration) - << 1 /* declaration */ << R << FixItHint::CreateRemoval(R); + return Actions.BuildDeclaratorGroup(DeclsInGroup, /*MayContainAuto*/false); +} - // Unfortunately, we have to bail out instead of recovering by - // ignoring the parameters, just in case the nested name specifier - // depends on the parameters. +Decl *Parser::ParseAliasDeclarationAfterDeclarator( + const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, + UsingDeclarator &D, SourceLocation &DeclEnd, AccessSpecifier AS, + ParsedAttributes &Attrs, Decl **OwnedType) { + if (ExpectAndConsume(tok::equal)) { + SkipUntil(tok::semi); return nullptr; } - // "typename" keyword is allowed for identifiers only, - // because it may be a type definition. - if (HasTypenameKeyword && Name.getKind() != UnqualifiedId::IK_Identifier) { - Diag(Name.getSourceRange().getBegin(), diag::err_typename_identifiers_only) - << FixItHint::CreateRemoval(SourceRange(TypenameLoc)); - // Proceed parsing, but reset the HasTypenameKeyword flag. - HasTypenameKeyword = false; + Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ? + diag::warn_cxx98_compat_alias_declaration : + diag::ext_alias_declaration); + + // Type alias templates cannot be specialized. + int SpecKind = -1; + if (TemplateInfo.Kind == ParsedTemplateInfo::Template && + D.Name.getKind() == UnqualifiedId::IK_TemplateId) + SpecKind = 0; + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization) + SpecKind = 1; + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + SpecKind = 2; + if (SpecKind != -1) { + SourceRange Range; + if (SpecKind == 0) + Range = SourceRange(D.Name.TemplateId->LAngleLoc, + D.Name.TemplateId->RAngleLoc); + else + Range = TemplateInfo.getSourceRange(); + Diag(Range.getBegin(), diag::err_alias_declaration_specialization) + << SpecKind << Range; + SkipUntil(tok::semi); + return nullptr; } - if (IsAliasDecl) { - TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; - MultiTemplateParamsArg TemplateParamsArg( - TemplateParams ? TemplateParams->data() : nullptr, - TemplateParams ? TemplateParams->size() : 0); - return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg, - UsingLoc, Name, Attrs.getList(), - TypeAlias, DeclFromDeclSpec); - } + // Name must be an identifier. + if (D.Name.getKind() != UnqualifiedId::IK_Identifier) { + Diag(D.Name.StartLocation, diag::err_alias_declaration_not_identifier); + // No removal fixit: can't recover from this. + SkipUntil(tok::semi); + return nullptr; + } else if (D.TypenameLoc.isValid()) + Diag(D.TypenameLoc, diag::err_alias_declaration_not_identifier) + << FixItHint::CreateRemoval(SourceRange( + D.TypenameLoc, + D.SS.isNotEmpty() ? D.SS.getEndLoc() : D.TypenameLoc)); + else if (D.SS.isNotEmpty()) + Diag(D.SS.getBeginLoc(), diag::err_alias_declaration_not_identifier) + << FixItHint::CreateRemoval(D.SS.getRange()); + if (D.EllipsisLoc.isValid()) + Diag(D.EllipsisLoc, diag::err_alias_declaration_pack_expansion) + << FixItHint::CreateRemoval(SourceRange(D.EllipsisLoc)); + + Decl *DeclFromDeclSpec = nullptr; + TypeResult TypeAlias = + ParseTypeName(nullptr, + TemplateInfo.Kind ? Declarator::AliasTemplateContext + : Declarator::AliasDeclContext, + AS, &DeclFromDeclSpec, &Attrs); + if (OwnedType) + *OwnedType = DeclFromDeclSpec; - return Actions.ActOnUsingDeclaration(getCurScope(), AS, - /* HasUsingKeyword */ true, UsingLoc, - SS, Name, Attrs.getList(), - HasTypenameKeyword, TypenameLoc); + // Eat ';'. + DeclEnd = Tok.getLocation(); + if (ExpectAndConsume(tok::semi, diag::err_expected_after, + !Attrs.empty() ? "attributes list" + : "alias declaration")) + SkipUntil(tok::semi); + + TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; + MultiTemplateParamsArg TemplateParamsArg( + TemplateParams ? TemplateParams->data() : nullptr, + TemplateParams ? TemplateParams->size() : 0); + return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg, + UsingLoc, D.Name, Attrs.getList(), + TypeAlias, DeclFromDeclSpec); } /// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration. @@ -1742,7 +1849,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TParams = MultiTemplateParamsArg(&(*TemplateParams)[0], TemplateParams->size()); - handleDeclspecAlignBeforeClassKey(attrs, DS, TUK); + stripTypeAttributesOffDeclSpec(attrs, DS, TUK); // Declaration or definition of a class type TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc, @@ -1995,7 +2102,8 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, LateMethod->DefaultArgs.reserve(FTI.NumParams); for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) LateMethod->DefaultArgs.push_back(LateParsedDefaultArgument( - FTI.Params[ParamIdx].Param, FTI.Params[ParamIdx].DefaultArgTokens)); + FTI.Params[ParamIdx].Param, + std::move(FTI.Params[ParamIdx].DefaultArgTokens))); } } @@ -2005,6 +2113,7 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, /// virt-specifier: /// override /// final +/// __final VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const { if (!getLangOpts().CPlusPlus || Tok.isNot(tok::identifier)) return VirtSpecifiers::VS_None; @@ -2014,6 +2123,8 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const { // Initialize the contextual keywords. if (!Ident_final) { Ident_final = &PP.getIdentifierTable().get("final"); + if (getLangOpts().GNUKeywords) + Ident_GNU_final = &PP.getIdentifierTable().get("__final"); if (getLangOpts().MicrosoftExt) Ident_sealed = &PP.getIdentifierTable().get("sealed"); Ident_override = &PP.getIdentifierTable().get("override"); @@ -2028,6 +2139,9 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const { if (II == Ident_final) return VirtSpecifiers::VS_Final; + if (II == Ident_GNU_final) + return VirtSpecifiers::VS_GNU_Final; + return VirtSpecifiers::VS_None; } @@ -2067,6 +2181,8 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, << VirtSpecifiers::getSpecifierName(Specifier); } else if (Specifier == VirtSpecifiers::VS_Sealed) { Diag(Tok.getLocation(), diag::ext_ms_sealed_keyword); + } else if (Specifier == VirtSpecifiers::VS_GNU_Final) { + Diag(Tok.getLocation(), diag::ext_warn_gnu_final); } else { Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 @@ -2083,6 +2199,7 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, bool Parser::isCXX11FinalKeyword() const { VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(); return Specifier == VirtSpecifiers::VS_Final || + Specifier == VirtSpecifiers::VS_GNU_Final || Specifier == VirtSpecifiers::VS_Sealed; } @@ -2181,7 +2298,7 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq( if (!(Function.TypeQuals & TypeQual)) { std::string Name(FixItName); Name += " "; - Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name.c_str()); + Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name); Function.TypeQuals |= TypeQual; *QualifierLoc = SpecLoc.getRawEncoding(); } @@ -2322,10 +2439,9 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration( - getCurScope(), AS, - /* HasUsingKeyword */ false, SourceLocation(), SS, Name, - /* AttrList */ nullptr, - /* HasTypenameKeyword */ false, SourceLocation()))); + getCurScope(), AS, /*UsingLoc*/ SourceLocation(), + /*TypenameLoc*/ SourceLocation(), SS, Name, + /*EllipsisLoc*/ SourceLocation(), /*AttrList*/ nullptr))); } } @@ -2380,8 +2496,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } SourceLocation DeclEnd; // Otherwise, it must be a using-declaration or an alias-declaration. - return DeclGroupPtrTy::make(DeclGroupRef(ParseUsingDeclaration( - Declarator::MemberContext, TemplateInfo, UsingLoc, DeclEnd, AS))); + return ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo, + UsingLoc, DeclEnd, AS); } // Hold late-parsed attributes so we can attach a Decl to them later. @@ -2996,6 +3112,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) { VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(Tok); assert((Specifier == VirtSpecifiers::VS_Final || + Specifier == VirtSpecifiers::VS_GNU_Final || Specifier == VirtSpecifiers::VS_Sealed) && "not a class definition"); FinalLoc = ConsumeToken(); @@ -3011,6 +3128,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, << VirtSpecifiers::getSpecifierName(Specifier); else if (Specifier == VirtSpecifiers::VS_Sealed) Diag(FinalLoc, diag::ext_ms_sealed_keyword); + else if (Specifier == VirtSpecifiers::VS_GNU_Final) + Diag(FinalLoc, diag::ext_warn_gnu_final); // Parse any C++11 attributes after 'final' keyword. // These attributes are not allowed to appear here, @@ -3456,7 +3575,11 @@ static void diagnoseDynamicExceptionSpecification( Parser &P, SourceRange Range, bool IsNoexcept) { if (P.getLangOpts().CPlusPlus11) { const char *Replacement = IsNoexcept ? "noexcept" : "noexcept(false)"; - P.Diag(Range.getBegin(), diag::warn_exception_spec_deprecated) << Range; + P.Diag(Range.getBegin(), + P.getLangOpts().CPlusPlus1z && !IsNoexcept + ? diag::ext_dynamic_exception_spec + : diag::warn_exception_spec_deprecated) + << Range; P.Diag(Range.getBegin(), diag::note_exception_spec_deprecated) << Replacement << FixItHint::CreateReplacement(Range, Replacement); } @@ -3655,8 +3778,8 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName, return true; case AttributeList::AT_WarnUnusedResult: return !ScopeName && AttrName->getName().equals("nodiscard"); - case AttributeList::AT_Unused:
- return !ScopeName && AttrName->getName().equals("maybe_unused");
+ case AttributeList::AT_Unused: + return !ScopeName && AttrName->getName().equals("maybe_unused"); default: return false; } @@ -3913,6 +4036,93 @@ SourceLocation Parser::SkipCXX11Attributes() { return EndLoc; } +/// Parse uuid() attribute when it appears in a [] Microsoft attribute. +void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) { + assert(Tok.is(tok::identifier) && "Not a Microsoft attribute list"); + IdentifierInfo *UuidIdent = Tok.getIdentifierInfo(); + assert(UuidIdent->getName() == "uuid" && "Not a Microsoft attribute list"); + + SourceLocation UuidLoc = Tok.getLocation(); + ConsumeToken(); + + // Ignore the left paren location for now. + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { + Diag(Tok, diag::err_expected) << tok::l_paren; + return; + } + + ArgsVector ArgExprs; + if (Tok.is(tok::string_literal)) { + // Easy case: uuid("...") -- quoted string. + ExprResult StringResult = ParseStringLiteralExpression(); + if (StringResult.isInvalid()) + return; + ArgExprs.push_back(StringResult.get()); + } else { + // something like uuid({000000A0-0000-0000-C000-000000000049}) -- no + // quotes in the parens. Just append the spelling of all tokens encountered + // until the closing paren. + + SmallString<42> StrBuffer; // 2 "", 36 bytes UUID, 2 optional {}, 1 nul + StrBuffer += "\""; + + // Since none of C++'s keywords match [a-f]+, accepting just tok::l_brace, + // tok::r_brace, tok::minus, tok::identifier (think C000) and + // tok::numeric_constant (0000) should be enough. But the spelling of the + // uuid argument is checked later anyways, so there's no harm in accepting + // almost anything here. + // cl is very strict about whitespace in this form and errors out if any + // is present, so check the space flags on the tokens. + SourceLocation StartLoc = Tok.getLocation(); + while (Tok.isNot(tok::r_paren)) { + if (Tok.hasLeadingSpace() || Tok.isAtStartOfLine()) { + Diag(Tok, diag::err_attribute_uuid_malformed_guid); + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + SmallString<16> SpellingBuffer; + SpellingBuffer.resize(Tok.getLength() + 1); + bool Invalid = false; + StringRef TokSpelling = PP.getSpelling(Tok, SpellingBuffer, &Invalid); + if (Invalid) { + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + StrBuffer += TokSpelling; + ConsumeAnyToken(); + } + StrBuffer += "\""; + + if (Tok.hasLeadingSpace() || Tok.isAtStartOfLine()) { + Diag(Tok, diag::err_attribute_uuid_malformed_guid); + ConsumeParen(); + return; + } + + // Pretend the user wrote the appropriate string literal here. + // ActOnStringLiteral() copies the string data into the literal, so it's + // ok that the Token points to StrBuffer. + Token Toks[1]; + Toks[0].startToken(); + Toks[0].setKind(tok::string_literal); + Toks[0].setLocation(StartLoc); + Toks[0].setLiteralData(StrBuffer.data()); + Toks[0].setLength(StrBuffer.size()); + StringLiteral *UuidString = + cast<StringLiteral>(Actions.ActOnStringLiteral(Toks, nullptr).get()); + ArgExprs.push_back(UuidString); + } + + if (!T.consumeClose()) { + // FIXME: Warn that this syntax is deprecated, with a Fix-It suggesting + // using __declspec(uuid()) instead. + Attrs.addNew(UuidIdent, SourceRange(UuidLoc, T.getCloseLocation()), nullptr, + SourceLocation(), ArgExprs.data(), ArgExprs.size(), + AttributeList::AS_Microsoft); + } +} + /// ParseMicrosoftAttributes - Parse Microsoft attributes [Attr] /// /// [MS] ms-attribute: @@ -3929,7 +4139,18 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, // FIXME: If this is actually a C++11 attribute, parse it as one. BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); - SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch); + + // Skip most ms attributes except for a whitelist. + while (true) { + SkipUntil(tok::r_square, tok::identifier, StopAtSemi | StopBeforeMatch); + if (Tok.isNot(tok::identifier)) // ']', but also eof + break; + if (Tok.getIdentifierInfo()->getName() == "uuid") + ParseMicrosoftUuidAttributeArgs(attrs); + else + ConsumeToken(); + } + T.consumeClose(); if (endLoc) *endLoc = T.getCloseLocation(); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 3e87a73aafe8..caf2320f8fc1 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -21,15 +21,14 @@ /// //===----------------------------------------------------------------------===// -#include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/PrettyStackTrace.h" +#include "clang/Parse/Parser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/TypoCorrection.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" using namespace clang; @@ -886,7 +885,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // Allow the base to be 'super' if in an objc-method. (&II == Ident_super && getCurScope()->isInObjcMethodScope()))) { ConsumeToken(); - + + if (Tok.is(tok::code_completion) && &II != Ident_super) { + Actions.CodeCompleteObjCClassPropertyRefExpr( + getCurScope(), II, ILoc, ExprStatementTokLoc == ILoc); + cutOffParsing(); + return ExprError(); + } // Allow either an identifier or the keyword 'class' (in C++). if (Tok.isNot(tok::identifier) && !(getLangOpts().CPlusPlus && Tok.is(tok::kw_class))) { @@ -1647,9 +1652,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (Tok.is(tok::code_completion)) { // Code completion for a member access expression. - Actions.CodeCompleteMemberReferenceExpr(getCurScope(), LHS.get(), - OpLoc, OpKind == tok::arrow); - + Actions.CodeCompleteMemberReferenceExpr( + getCurScope(), LHS.get(), OpLoc, OpKind == tok::arrow, + ExprStatementTokLoc == LHS.get()->getLocStart()); + cutOffParsing(); return ExprError(); } @@ -2836,6 +2842,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, + /*DeclsInPrototype=*/None, CaretLoc, CaretLoc, ParamInfo), attrs, CaretLoc); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 85c1301fc967..ca1b3b1ad01b 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -100,48 +100,6 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, /*AtDigraph*/false); } -/// \brief Emits an error for a left parentheses after a double colon. -/// -/// When a '(' is found after a '::', emit an error. Attempt to fix the token -/// stream by removing the '(', and the matching ')' if found. -void Parser::CheckForLParenAfterColonColon() { - if (!Tok.is(tok::l_paren)) - return; - - Token LParen = Tok; - Token NextTok = GetLookAheadToken(1); - Token StarTok = NextTok; - // Check for (identifier or (*identifier - Token IdentifierTok = StarTok.is(tok::star) ? GetLookAheadToken(2) : StarTok; - if (IdentifierTok.isNot(tok::identifier)) - return; - // Eat the '('. - ConsumeParen(); - Token RParen; - RParen.setLocation(SourceLocation()); - // Do we have a ')' ? - NextTok = StarTok.is(tok::star) ? GetLookAheadToken(2) : GetLookAheadToken(1); - if (NextTok.is(tok::r_paren)) { - RParen = NextTok; - // Eat the '*' if it is present. - if (StarTok.is(tok::star)) - ConsumeToken(); - // Eat the identifier. - ConsumeToken(); - // Add the identifier token back. - PP.EnterToken(IdentifierTok); - // Add the '*' back if it was present. - if (StarTok.is(tok::star)) - PP.EnterToken(StarTok); - // Eat the ')'. - ConsumeParen(); - } - - Diag(LParen.getLocation(), diag::err_paren_after_colon_colon) - << FixItHint::CreateRemoval(LParen.getLocation()) - << FixItHint::CreateRemoval(RParen.getLocation()); -} - /// \brief Parse global scope or nested-name-specifier if present. /// /// Parses a C++ global scope specifier ('::') or nested-name-specifier (which @@ -237,8 +195,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, if (Actions.ActOnCXXGlobalScopeSpecifier(ConsumeToken(), SS)) return true; - CheckForLParenAfterColonColon(); - HasScopeSpecifier = true; } } @@ -427,13 +383,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // namespace-name '::' // nested-name-specifier identifier '::' Token Next = NextToken(); - + Sema::NestedNameSpecInfo IdInfo(&II, Tok.getLocation(), Next.getLocation(), + ObjectType); + // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover // and emit a fixit hint for it. if (Next.is(tok::colon) && !ColonIsSacred) { - if (Actions.IsInvalidUnlessNestedName(getCurScope(), SS, II, - Tok.getLocation(), - Next.getLocation(), ObjectType, + if (Actions.IsInvalidUnlessNestedName(getCurScope(), SS, IdInfo, EnteringContext) && // If the token after the colon isn't an identifier, it's still an // error, but they probably meant something else strange so don't @@ -459,8 +415,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, if (Next.is(tok::coloncolon)) { if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) && - !Actions.isNonTypeNestedNameSpecifier( - getCurScope(), SS, Tok.getLocation(), II, ObjectType)) { + !Actions.isNonTypeNestedNameSpecifier(getCurScope(), SS, IdInfo)) { *MayBePseudoDestructor = true; return false; } @@ -492,12 +447,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, Token ColonColon = Tok; SourceLocation CCLoc = ConsumeToken(); - CheckForLParenAfterColonColon(); - bool IsCorrectedToColon = false; bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr; - if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc, - ObjectType, EnteringContext, SS, + if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), IdInfo, + EnteringContext, SS, false, CorrectionFlagPtr)) { // Identifier is not recognized as a nested name, but we can have // mistyped '::' instead of ':'. @@ -949,6 +902,8 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, SourceLocation StartLoc = Tok.getLocation(); InMessageExpressionRAIIObject MaybeInMessageExpression(*this, true); Init = ParseInitializer(); + if (!Init.isInvalid()) + Init = Actions.CorrectDelayedTyposInExpr(Init.get()); if (Tok.getLocation() != StartLoc) { // Back out the lexing of the token after the initializer. @@ -1003,6 +958,7 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, // return y; // } // }; + // } // If x was not const, the second use would require 'L' to capture, and // that would be an error. @@ -1053,6 +1009,58 @@ bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) { return false; } +static void +tryConsumeMutableOrConstexprToken(Parser &P, SourceLocation &MutableLoc, + SourceLocation &ConstexprLoc, + SourceLocation &DeclEndLoc) { + assert(MutableLoc.isInvalid()); + assert(ConstexprLoc.isInvalid()); + // Consume constexpr-opt mutable-opt in any sequence, and set the DeclEndLoc + // to the final of those locations. Emit an error if we have multiple + // copies of those keywords and recover. + + while (true) { + switch (P.getCurToken().getKind()) { + case tok::kw_mutable: { + if (MutableLoc.isValid()) { + P.Diag(P.getCurToken().getLocation(), + diag::err_lambda_decl_specifier_repeated) + << 0 << FixItHint::CreateRemoval(P.getCurToken().getLocation()); + } + MutableLoc = P.ConsumeToken(); + DeclEndLoc = MutableLoc; + break /*switch*/; + } + case tok::kw_constexpr: + if (ConstexprLoc.isValid()) { + P.Diag(P.getCurToken().getLocation(), + diag::err_lambda_decl_specifier_repeated) + << 1 << FixItHint::CreateRemoval(P.getCurToken().getLocation()); + } + ConstexprLoc = P.ConsumeToken(); + DeclEndLoc = ConstexprLoc; + break /*switch*/; + default: + return; + } + } +} + +static void +addConstexprToLambdaDeclSpecifier(Parser &P, SourceLocation ConstexprLoc, + DeclSpec &DS) { + if (ConstexprLoc.isValid()) { + P.Diag(ConstexprLoc, !P.getLangOpts().CPlusPlus1z + ? diag::ext_constexpr_on_lambda_cxx1z + : diag::warn_cxx14_compat_constexpr_on_lambda); + const char *PrevSpec = nullptr; + unsigned DiagID = 0; + DS.SetConstexprSpec(ConstexprLoc, PrevSpec, DiagID); + assert(PrevSpec == nullptr && DiagID == 0 && + "Constexpr cannot have been set previously!"); + } +} + /// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda /// expression. ExprResult Parser::ParseLambdaExpressionAfterIntroducer( @@ -1072,7 +1080,27 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DeclSpec DS(AttrFactory); Declarator D(DS, Declarator::LambdaExprContext); TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); - Actions.PushLambdaScope(); + Actions.PushLambdaScope(); + + ParsedAttributes Attr(AttrFactory); + SourceLocation DeclLoc = Tok.getLocation(); + if (getLangOpts().CUDA) { + // In CUDA code, GNU attributes are allowed to appear immediately after the + // "[...]", even if there is no "(...)" before the lambda body. + MaybeParseGNUAttributes(D); + } + + // Helper to emit a warning if we see a CUDA host/device/global attribute + // after '(...)'. nvcc doesn't accept this. + auto WarnIfHasCUDATargetAttr = [&] { + if (getLangOpts().CUDA) + for (auto *A = Attr.getList(); A != nullptr; A = A->getNext()) + if (A->getKind() == AttributeList::AT_CUDADevice || + A->getKind() == AttributeList::AT_CUDAHost || + A->getKind() == AttributeList::AT_CUDAGlobal) + Diag(A->getLoc(), diag::warn_cuda_attr_lambda_position) + << A->getName()->getName(); + }; TypeResult TrailingReturnType; if (Tok.is(tok::l_paren)) { @@ -1081,13 +1109,11 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( Scope::FunctionDeclarationScope | Scope::DeclScope); - SourceLocation DeclEndLoc; BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); SourceLocation LParenLoc = T.getOpenLocation(); // Parse parameter-declaration-clause. - ParsedAttributes Attr(AttrFactory); SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo; SourceLocation EllipsisLoc; @@ -1101,7 +1127,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( } T.consumeClose(); SourceLocation RParenLoc = T.getCloseLocation(); - DeclEndLoc = RParenLoc; + SourceLocation DeclEndLoc = RParenLoc; // GNU-style attributes must be parsed before the mutable specifier to be // compatible with GCC. @@ -1111,10 +1137,13 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( // compatible with MSVC. MaybeParseMicrosoftDeclSpecs(Attr, &DeclEndLoc); - // Parse 'mutable'[opt]. + // Parse mutable-opt and/or constexpr-opt, and update the DeclEndLoc. SourceLocation MutableLoc; - if (TryConsumeToken(tok::kw_mutable, MutableLoc)) - DeclEndLoc = MutableLoc; + SourceLocation ConstexprLoc; + tryConsumeMutableOrConstexprToken(*this, MutableLoc, ConstexprLoc, + DeclEndLoc); + + addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); // Parse exception-specification[opt]. ExceptionSpecificationType ESpecType = EST_None; @@ -1149,6 +1178,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( PrototypeScope.Exit(); + WarnIfHasCUDATargetAttr(); + SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, /*isAmbiguous=*/false, @@ -1169,10 +1200,12 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, /*ExceptionSpecTokens*/nullptr, + /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D, TrailingReturnType), Attr, DeclEndLoc); - } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute) || + } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute, + tok::kw_constexpr) || (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) { // It's common to forget that one needs '()' before 'mutable', an attribute // specifier, or the result type. Deal with this. @@ -1182,18 +1215,17 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( case tok::arrow: TokKind = 1; break; case tok::kw___attribute: case tok::l_square: TokKind = 2; break; + case tok::kw_constexpr: TokKind = 3; break; default: llvm_unreachable("Unknown token kind"); } Diag(Tok, diag::err_lambda_missing_parens) << TokKind << FixItHint::CreateInsertion(Tok.getLocation(), "() "); - SourceLocation DeclLoc = Tok.getLocation(); SourceLocation DeclEndLoc = DeclLoc; // GNU-style attributes must be parsed before the mutable specifier to be // compatible with GCC. - ParsedAttributes Attr(AttrFactory); MaybeParseGNUAttributes(Attr, &DeclEndLoc); // Parse 'mutable', if it's there. @@ -1214,6 +1246,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DeclEndLoc = Range.getEnd(); } + WarnIfHasCUDATargetAttr(); + SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, /*isAmbiguous=*/false, @@ -1236,11 +1270,11 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, + /*DeclsInPrototype=*/None, DeclLoc, DeclEndLoc, D, TrailingReturnType), Attr, DeclEndLoc); } - // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using // it. @@ -1711,6 +1745,10 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, } case ConditionOrInitStatement::InitStmtDecl: { + Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z + ? diag::warn_cxx14_compat_init_statement + : diag::ext_init_statement) + << (CK == Sema::ConditionKind::Switch); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy DG = ParseSimpleDeclaration( Declarator::InitStmtContext, DeclEnd, attrs, /*RequireSemi=*/true); diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 2cdb9d3a22a6..4a68942f6d2c 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -11,13 +11,12 @@ // //===----------------------------------------------------------------------===// -#include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" #include "clang/Sema/Designator.h" #include "clang/Sema/Scope.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/raw_ostream.h" using namespace clang; diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 67abe5839bfe..81761bf8d2d8 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -344,9 +344,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, protocols, protocolLocs, EndProtoLoc, /*consumeLastToken=*/true, /*warnOnIncompleteProtocols=*/true); + if (Tok.is(tok::eof)) + return nullptr; } } - + // Next, we need to check for any protocol references. if (LAngleLoc.isValid()) { if (!ProtocolIdents.empty()) { @@ -367,7 +369,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, } if (Tok.isNot(tok::less)) - Actions.ActOnTypedefedProtocols(protocols, superClassId, superClassLoc); + Actions.ActOnTypedefedProtocols(protocols, protocolLocs, + superClassId, superClassLoc); Decl *ClsType = Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc, @@ -1034,7 +1037,7 @@ IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) { case tok::caretequal: { std::string ThisTok(PP.getSpelling(Tok)); if (isLetter(ThisTok[0])) { - IdentifierInfo *II = &PP.getIdentifierTable().get(ThisTok.data()); + IdentifierInfo *II = &PP.getIdentifierTable().get(ThisTok); Tok.setKind(tok::identifier); SelectorLoc = ConsumeToken(); return II; @@ -1814,6 +1817,8 @@ void Parser::parseObjCTypeArgsAndProtocolQualifiers( protocolRAngleLoc, consumeLastToken, /*warnOnIncompleteProtocols=*/false); + if (Tok.is(tok::eof)) // Nothing else to do here... + return; // An Objective-C object pointer followed by type arguments // can then be followed again by a set of protocol references, e.g., @@ -1862,6 +1867,9 @@ TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers( protocols, protocolLocs, protocolRAngleLoc, consumeLastToken); + if (Tok.is(tok::eof)) + return true; // Invalid type result. + // Compute the location of the last token. if (consumeLastToken) endLoc = PrevTokLocation; @@ -2238,7 +2246,6 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { while (!ObjCImplParsing.isFinished() && !isEofOrEom()) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); - MaybeParseMicrosoftAttributes(attrs); if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) { DeclGroupRef DG = DGP.get(); DeclsInGroup.append(DG.begin(), DG.end()); @@ -2766,6 +2773,7 @@ StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { return Actions.ActOnNullStmt(Tok.getLocation()); } + ExprStatementTokLoc = AtLoc; ExprResult Res(ParseExpressionWithLeadingAt(AtLoc)); if (Res.isInvalid()) { // If the expression is invalid, skip ahead to the next semicolon. Not @@ -2862,7 +2870,11 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { return ParseAvailabilityCheckExpr(AtLoc); default: { const char *str = nullptr; - if (GetLookAheadToken(1).is(tok::l_brace)) { + // Only provide the @try/@finally/@autoreleasepool fixit when we're sure + // that this is a proper statement where such directives could actually + // occur. + if (GetLookAheadToken(1).is(tok::l_brace) && + ExprStatementTokLoc == AtLoc) { char ch = Tok.getIdentifierInfo()->getNameStart()[0]; str = ch == 't' ? "try" @@ -3416,6 +3428,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) { ExprVector ElementExprs; // array elements. ConsumeBracket(); // consume the l_square. + bool HasInvalidEltExpr = false; while (Tok.isNot(tok::r_square)) { // Parse list of array element expressions (all must be id types). ExprResult Res(ParseAssignmentExpression()); @@ -3427,11 +3440,15 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) { return Res; } + Res = Actions.CorrectDelayedTyposInExpr(Res.get()); + if (Res.isInvalid()) + HasInvalidEltExpr = true; + // Parse the ellipsis that indicates a pack expansion. if (Tok.is(tok::ellipsis)) Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken()); if (Res.isInvalid()) - return true; + HasInvalidEltExpr = true; ElementExprs.push_back(Res.get()); @@ -3442,6 +3459,10 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) { << tok::comma); } SourceLocation EndLoc = ConsumeBracket(); // location of ']' + + if (HasInvalidEltExpr) + return ExprError(); + MultiExprArg Args(ElementExprs); return Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args); } @@ -3449,6 +3470,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) { ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { SmallVector<ObjCDictionaryElement, 4> Elements; // dictionary elements. ConsumeBrace(); // consume the l_square. + bool HasInvalidEltExpr = false; while (Tok.isNot(tok::r_brace)) { // Parse the comma separated key : value expressions. ExprResult KeyExpr; @@ -3478,7 +3500,15 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { return ValueExpr; } - // Parse the ellipsis that designates this as a pack expansion. + // Check the key and value for possible typos + KeyExpr = Actions.CorrectDelayedTyposInExpr(KeyExpr.get()); + ValueExpr = Actions.CorrectDelayedTyposInExpr(ValueExpr.get()); + if (KeyExpr.isInvalid() || ValueExpr.isInvalid()) + HasInvalidEltExpr = true; + + // Parse the ellipsis that designates this as a pack expansion. Do not + // ActOnPackExpansion here, leave it to template instantiation time where + // we can get better diagnostics. SourceLocation EllipsisLoc; if (getLangOpts().CPlusPlus) TryConsumeToken(tok::ellipsis, EllipsisLoc); @@ -3495,6 +3525,9 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { << tok::comma); } SourceLocation EndLoc = ConsumeBrace(); + + if (HasInvalidEltExpr) + return ExprError(); // Create the ObjCDictionaryLiteral. return Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc), diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index df7d9bc0d8c8..061721dfb8da 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "RAIIObjectsForParser.h" -#include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/StmtOpenMP.h" #include "clang/Parse/ParseDiagnostic.h" @@ -40,7 +39,9 @@ enum OpenMPDirectiveKindEx { OMPD_target_enter, OMPD_target_exit, OMPD_update, - OMPD_distribute_parallel + OMPD_distribute_parallel, + OMPD_teams_distribute_parallel, + OMPD_target_teams_distribute_parallel }; class ThreadprivateListParserHelper final { @@ -107,8 +108,18 @@ static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) { { OMPD_parallel, OMPD_sections, OMPD_parallel_sections }, { OMPD_taskloop, OMPD_simd, OMPD_taskloop_simd }, { OMPD_target, OMPD_parallel, OMPD_target_parallel }, + { OMPD_target, OMPD_simd, OMPD_target_simd }, { OMPD_target_parallel, OMPD_for, OMPD_target_parallel_for }, - { OMPD_target_parallel_for, OMPD_simd, OMPD_target_parallel_for_simd } + { OMPD_target_parallel_for, OMPD_simd, OMPD_target_parallel_for_simd }, + { OMPD_teams, OMPD_distribute, OMPD_teams_distribute }, + { OMPD_teams_distribute, OMPD_simd, OMPD_teams_distribute_simd }, + { OMPD_teams_distribute, OMPD_parallel, OMPD_teams_distribute_parallel }, + { OMPD_teams_distribute_parallel, OMPD_for, OMPD_teams_distribute_parallel_for }, + { OMPD_teams_distribute_parallel_for, OMPD_simd, OMPD_teams_distribute_parallel_for_simd }, + { OMPD_target, OMPD_teams, OMPD_target_teams }, + { OMPD_target_teams, OMPD_distribute, OMPD_target_teams_distribute }, + { OMPD_target_teams_distribute, OMPD_parallel, OMPD_target_teams_distribute_parallel }, + { OMPD_target_teams_distribute_parallel, OMPD_for, OMPD_target_teams_distribute_parallel_for } }; enum { CancellationPoint = 0, DeclareReduction = 1, TargetData = 2 }; auto Tok = P.getCurToken(); @@ -609,7 +620,6 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( if (AS == AS_none) { assert(TagType == DeclSpec::TST_unspecified); MaybeParseCXX11Attributes(Attrs); - MaybeParseMicrosoftAttributes(Attrs); ParsingDeclSpec PDS(*this); Ptr = ParseExternalDeclaration(Attrs, &PDS); } else { @@ -671,7 +681,6 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( Tok.isNot(tok::eof) && Tok.isNot(tok::r_brace)) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); - MaybeParseMicrosoftAttributes(attrs); ParseExternalDeclaration(attrs); if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) { TentativeParsingAction TPA(*this); @@ -741,6 +750,14 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_distribute_parallel_for_simd: case OMPD_distribute_simd: case OMPD_target_parallel_for_simd: + case OMPD_target_simd: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + case OMPD_teams_distribute_parallel_for_simd: + case OMPD_teams_distribute_parallel_for: + case OMPD_target_teams: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_parallel_for: Diag(Tok, diag::err_omp_unexpected_directive) << getOpenMPDirectiveName(DKind); break; @@ -774,7 +791,12 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( /// 'target parallel' | 'target parallel for' | /// 'target update' | 'distribute parallel for' | /// 'distribute paralle for simd' | 'distribute simd' | -/// 'target parallel for simd' {clause} +/// 'target parallel for simd' | 'target simd' | +/// 'teams distribute' | 'teams distribute simd' | +/// 'teams distribute parallel for simd' | +/// 'teams distribute parallel for' | 'target teams' | +/// 'target teams distribute' | +/// 'target teams distribute parallel for' {clause} /// annot_pragma_openmp_end /// StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( @@ -882,7 +904,15 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: case OMPD_distribute_simd: - case OMPD_target_parallel_for_simd: { + case OMPD_target_parallel_for_simd: + case OMPD_target_simd: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + case OMPD_teams_distribute_parallel_for_simd: + case OMPD_teams_distribute_parallel_for: + case OMPD_target_teams: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_parallel_for: { ConsumeToken(); // Parse directive name of the 'critical' directive if any. if (DKind == OMPD_critical) { @@ -1441,15 +1471,19 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind) { } else { assert(Kind == OMPC_if); KLoc.push_back(Tok.getLocation()); + TentativeParsingAction TPA(*this); Arg.push_back(ParseOpenMPDirectiveKind(*this)); if (Arg.back() != OMPD_unknown) { ConsumeToken(); - if (Tok.is(tok::colon)) + if (Tok.is(tok::colon) && getLangOpts().OpenMP > 40) { + TPA.Commit(); DelimLoc = ConsumeToken(); - else - Diag(Tok, diag::warn_pragma_expected_colon) - << "directive name modifier"; - } + } else { + TPA.Revert(); + Arg.back() = OMPD_unknown; + } + } else + TPA.Revert(); } bool NeedAnExpression = (Kind == OMPC_schedule && DelimLoc.isValid()) || diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index bff5d1170fe0..2dc6a0739bc8 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -161,6 +161,22 @@ struct PragmaMSRuntimeChecksHandler : public EmptyPragmaHandler { PragmaMSRuntimeChecksHandler() : EmptyPragmaHandler("runtime_checks") {} }; +struct PragmaMSIntrinsicHandler : public PragmaHandler { + PragmaMSIntrinsicHandler() : PragmaHandler("intrinsic") {} + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken) override; +}; + +struct PragmaForceCUDAHostDeviceHandler : public PragmaHandler { + PragmaForceCUDAHostDeviceHandler(Sema &Actions) + : PragmaHandler("force_cuda_host_device"), Actions(Actions) {} + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken) override; + +private: + Sema &Actions; +}; + } // end namespace void Parser::initializePragmaHandlers() { @@ -229,6 +245,14 @@ void Parser::initializePragmaHandlers() { PP.AddPragmaHandler(MSSection.get()); MSRuntimeChecks.reset(new PragmaMSRuntimeChecksHandler()); PP.AddPragmaHandler(MSRuntimeChecks.get()); + MSIntrinsic.reset(new PragmaMSIntrinsicHandler()); + PP.AddPragmaHandler(MSIntrinsic.get()); + } + + if (getLangOpts().CUDA) { + CUDAForceHostDeviceHandler.reset( + new PragmaForceCUDAHostDeviceHandler(Actions)); + PP.AddPragmaHandler("clang", CUDAForceHostDeviceHandler.get()); } OptimizeHandler.reset(new PragmaOptimizeHandler(Actions)); @@ -297,6 +321,13 @@ void Parser::resetPragmaHandlers() { MSSection.reset(); PP.RemovePragmaHandler(MSRuntimeChecks.get()); MSRuntimeChecks.reset(); + PP.RemovePragmaHandler(MSIntrinsic.get()); + MSIntrinsic.reset(); + } + + if (getLangOpts().CUDA) { + PP.RemovePragmaHandler("clang", CUDAForceHostDeviceHandler.get()); + CUDAForceHostDeviceHandler.reset(); } PP.RemovePragmaHandler("STDC", FPContractHandler.get()); @@ -455,42 +486,48 @@ StmtResult Parser::HandlePragmaCaptured() } namespace { - typedef llvm::PointerIntPair<IdentifierInfo *, 1, bool> OpenCLExtData; + enum OpenCLExtState : char { + Disable, Enable, Begin, End + }; + typedef std::pair<const IdentifierInfo *, OpenCLExtState> OpenCLExtData; } void Parser::HandlePragmaOpenCLExtension() { assert(Tok.is(tok::annot_pragma_opencl_extension)); - OpenCLExtData data = - OpenCLExtData::getFromOpaqueValue(Tok.getAnnotationValue()); - unsigned state = data.getInt(); - IdentifierInfo *ename = data.getPointer(); + OpenCLExtData *Data = static_cast<OpenCLExtData*>(Tok.getAnnotationValue()); + auto State = Data->second; + auto Ident = Data->first; SourceLocation NameLoc = Tok.getLocation(); ConsumeToken(); // The annotation token. - OpenCLOptions &f = Actions.getOpenCLOptions(); - auto CLVer = getLangOpts().OpenCLVersion; - auto &Supp = getTargetInfo().getSupportedOpenCLOpts(); + auto &Opt = Actions.getOpenCLOptions(); + auto Name = Ident->getName(); // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions, // overriding all previously issued extension directives, but only if the // behavior is set to disable." - if (state == 0 && ename->isStr("all")) { -#define OPENCLEXT(nm) \ - if (Supp.is_##nm##_supported_extension(CLVer)) \ - f.nm = 0; -#include "clang/Basic/OpenCLExtensions.def" - } -#define OPENCLEXT(nm) else if (ename->isStr(#nm)) \ - if (Supp.is_##nm##_supported_extension(CLVer)) \ - f.nm = state; \ - else if (Supp.is_##nm##_supported_core(CLVer)) \ - PP.Diag(NameLoc, diag::warn_pragma_extension_is_core) << ename; \ - else \ - PP.Diag(NameLoc, diag::warn_pragma_unsupported_extension) << ename; -#include "clang/Basic/OpenCLExtensions.def" - else { - PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename; - return; - } + if (Name == "all") { + if (State == Disable) + Opt.disableAll(); + else + PP.Diag(NameLoc, diag::warn_pragma_expected_predicate) << 1; + } else if (State == Begin) { + if (!Opt.isKnown(Name) || + !Opt.isSupported(Name, getLangOpts().OpenCLVersion)) { + Opt.support(Name); + } + Actions.setCurrentOpenCLExtension(Name); + } else if (State == End) { + if (Name != Actions.getCurrentOpenCLExtension()) + PP.Diag(NameLoc, diag::warn_pragma_begin_end_mismatch); + Actions.setCurrentOpenCLExtension(""); + } else if (!Opt.isKnown(Name)) + PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << Ident; + else if (Opt.isSupportedExtension(Name, getLangOpts().OpenCLVersion)) + Opt.enable(Name, State == Enable); + else if (Opt.isSupportedCore(Name, getLangOpts().OpenCLVersion)) + PP.Diag(NameLoc, diag::warn_pragma_extension_is_core) << Ident; + else + PP.Diag(NameLoc, diag::warn_pragma_unsupported_extension) << Ident; } void Parser::HandlePragmaMSPointersToMembers() { @@ -1410,29 +1447,34 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, "OPENCL"; return; } - IdentifierInfo *ename = Tok.getIdentifierInfo(); + IdentifierInfo *Ext = Tok.getIdentifierInfo(); SourceLocation NameLoc = Tok.getLocation(); PP.Lex(Tok); if (Tok.isNot(tok::colon)) { - PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_colon) << ename; + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_colon) << Ext; return; } PP.Lex(Tok); if (Tok.isNot(tok::identifier)) { - PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable); + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_predicate) << 0; return; } - IdentifierInfo *op = Tok.getIdentifierInfo(); - - unsigned state; - if (op->isStr("enable")) { - state = 1; - } else if (op->isStr("disable")) { - state = 0; - } else { - PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable); + IdentifierInfo *Pred = Tok.getIdentifierInfo(); + + OpenCLExtState State; + if (Pred->isStr("enable")) { + State = Enable; + } else if (Pred->isStr("disable")) { + State = Disable; + } else if (Pred->isStr("begin")) + State = Begin; + else if (Pred->isStr("end")) + State = End; + else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_predicate) + << Ext->isStr("all"); return; } SourceLocation StateLoc = Tok.getLocation(); @@ -1444,19 +1486,21 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, return; } - OpenCLExtData data(ename, state); + auto Info = PP.getPreprocessorAllocator().Allocate<OpenCLExtData>(1); + Info->first = Ext; + Info->second = State; MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), 1); Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_opencl_extension); Toks[0].setLocation(NameLoc); - Toks[0].setAnnotationValue(data.getOpaqueValue()); + Toks[0].setAnnotationValue(static_cast<void*>(Info)); Toks[0].setAnnotationEndLoc(StateLoc); PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); if (PP.getPPCallbacks()) - PP.getPPCallbacks()->PragmaOpenCLExtension(NameLoc, ename, - StateLoc, state); + PP.getPPCallbacks()->PragmaOpenCLExtension(NameLoc, Ext, + StateLoc, State); } /// \brief Handle '#pragma omp ...' when OpenMP is disabled. @@ -2127,3 +2171,76 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP, PP.EnterTokenStream(std::move(TokenArray), 1, /*DisableMacroExpansion=*/false); } + +/// \brief Handle the Microsoft \#pragma intrinsic extension. +/// +/// The syntax is: +/// \code +/// #pragma intrinsic(memset) +/// #pragma intrinsic(strlen, memcpy) +/// \endcode +/// +/// Pragma intrisic tells the compiler to use a builtin version of the +/// function. Clang does it anyway, so the pragma doesn't really do anything. +/// Anyway, we emit a warning if the function specified in \#pragma intrinsic +/// isn't an intrinsic in clang and suggest to include intrin.h. +void PragmaMSIntrinsicHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &Tok) { + PP.Lex(Tok); + + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) + << "intrinsic"; + return; + } + PP.Lex(Tok); + + bool SuggestIntrinH = !PP.isMacroDefined("__INTRIN_H"); + + while (Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + if (!II->getBuiltinID()) + PP.Diag(Tok.getLocation(), diag::warn_pragma_intrinsic_builtin) + << II << SuggestIntrinH; + + PP.Lex(Tok); + if (Tok.isNot(tok::comma)) + break; + PP.Lex(Tok); + } + + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) + << "intrinsic"; + return; + } + PP.Lex(Tok); + + if (Tok.isNot(tok::eod)) + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << "intrinsic"; +} +void PragmaForceCUDAHostDeviceHandler::HandlePragma( + Preprocessor &PP, PragmaIntroducerKind Introducer, Token &Tok) { + Token FirstTok = Tok; + + PP.Lex(Tok); + IdentifierInfo *Info = Tok.getIdentifierInfo(); + if (!Info || (!Info->isStr("begin") && !Info->isStr("end"))) { + PP.Diag(FirstTok.getLocation(), + diag::warn_pragma_force_cuda_host_device_bad_arg); + return; + } + + if (Info->isStr("begin")) + Actions.PushForceCUDAHostDevice(); + else if (!Actions.PopForceCUDAHostDevice()) + PP.Diag(FirstTok.getLocation(), + diag::err_pragma_cannot_end_force_cuda_host_device); + + PP.Lex(Tok); + if (!Tok.is(tok::eod)) + PP.Diag(FirstTok.getLocation(), + diag::warn_pragma_force_cuda_host_device_bad_arg); +} diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index fa8eb12044be..30e392fa3c94 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -12,18 +12,15 @@ // //===----------------------------------------------------------------------===// -#include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" -#include "clang/AST/ASTContext.h" #include "clang/Basic/Attributes.h" -#include "clang/Basic/Diagnostic.h" #include "clang/Basic/PrettyStackTrace.h" +#include "clang/Parse/Parser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/LoopHint.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" #include "clang/Sema/TypoCorrection.h" -#include "llvm/ADT/SmallString.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -209,7 +206,8 @@ Retry: } default: { - if ((getLangOpts().CPlusPlus || Allowed == ACK_Any) && + if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || + Allowed == ACK_Any) && isDeclarationStatement()) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, @@ -398,6 +396,8 @@ StmtResult Parser::ParseExprStatement() { // If a case keyword is missing, this is where it should be inserted. Token OldToken = Tok; + ExprStatementTokLoc = Tok.getLocation(); + // expression[opt] ';' ExprResult Expr(ParseExpression()); if (Expr.isInvalid()) { diff --git a/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp index 1f63dc257b86..293de78505ef 100644 --- a/lib/Parse/ParseStmtAsm.cpp +++ b/lib/Parse/ParseStmtAsm.cpp @@ -681,12 +681,12 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { // GNU asms accept, but warn, about type-qualifiers other than volatile. if (DS.getTypeQualifiers() & DeclSpec::TQ_const) - Diag(Loc, diag::w_asm_qualifier_ignored) << "const"; + Diag(Loc, diag::warn_asm_qualifier_ignored) << "const"; if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) - Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict"; + Diag(Loc, diag::warn_asm_qualifier_ignored) << "restrict"; // FIXME: Once GCC supports _Atomic, check whether it permits it here. if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) - Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic"; + Diag(Loc, diag::warn_asm_qualifier_ignored) << "_Atomic"; // Remember if this was a volatile asm. bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 6cf7b6d3dc55..6a09ea7abca0 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -11,12 +11,11 @@ // //===----------------------------------------------------------------------===// -#include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" -#include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" @@ -197,9 +196,12 @@ Parser::ParseSingleDeclarationAfterTemplate( ParsedAttributesWithRange prefixAttrs(AttrFactory); MaybeParseCXX11Attributes(prefixAttrs); - if (Tok.is(tok::kw_using)) - return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, - prefixAttrs); + if (Tok.is(tok::kw_using)) { + // FIXME: We should return the DeclGroup to the caller. + ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, + prefixAttrs); + return nullptr; + } // Parse the declaration specifiers, stealing any diagnostics from // the template parameters. diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 7703c33b8780..0ea3f8d95179 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -74,11 +74,18 @@ bool Parser::isCXXDeclarationStatement() { /// /// simple-declaration: /// decl-specifier-seq init-declarator-list[opt] ';' +/// decl-specifier-seq ref-qualifier[opt] '[' identifier-list ']' +/// brace-or-equal-initializer ';' [C++17] /// /// (if AllowForRangeDecl specified) /// for ( for-range-declaration : for-range-initializer ) statement +/// /// for-range-declaration: -/// attribute-specifier-seqopt type-specifier-seq declarator +/// decl-specifier-seq declarator +/// decl-specifier-seq ref-qualifier[opt] '[' identifier-list ']' +/// +/// In any of the above cases there can be a preceding attribute-specifier-seq, +/// but the caller is expected to handle that. bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) { // C++ 6.8p1: // There is an ambiguity in the grammar involving expression-statements and @@ -902,7 +909,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // '(' abstract-declarator ')' if (Tok.isOneOf(tok::kw___attribute, tok::kw___declspec, tok::kw___cdecl, tok::kw___stdcall, tok::kw___fastcall, tok::kw___thiscall, - tok::kw___vectorcall)) + tok::kw___regcall, tok::kw___vectorcall)) return TPResult::True; // attributes indicate declaration TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier); if (TPR != TPResult::Ambiguous) @@ -1051,6 +1058,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: + case tok::kw___regcall: case tok::kw___vectorcall: case tok::kw___unaligned: case tok::kw___vector: @@ -1344,6 +1352,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: + case tok::kw___regcall: case tok::kw___vectorcall: case tok::kw___w64: case tok::kw___sptr: diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index f968f995d53f..d8a4ea63153a 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -20,7 +20,6 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" -#include "llvm/Support/raw_ostream.h" using namespace clang; @@ -78,7 +77,6 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) Tok.setKind(tok::eof); Actions.CurScope = nullptr; NumCachedScopes = 0; - ParenCount = BracketCount = BraceCount = 0; CurParsedObjCImpl = nullptr; // Add #pragma handlers. These are removed and destroyed in the @@ -474,6 +472,7 @@ void Parser::Initialize() { Ident_final = nullptr; Ident_sealed = nullptr; Ident_override = nullptr; + Ident_GNU_final = nullptr; Ident_super = &PP.getIdentifierTable().get("super"); @@ -537,6 +536,36 @@ void Parser::LateTemplateParserCleanupCallback(void *P) { DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(((Parser *)P)->TemplateIds); } +bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) { + // C++ Modules TS: module-declaration must be the first declaration in the + // file. (There can be no preceding preprocessor directives, but we expect + // the lexer to check that.) + if (Tok.is(tok::kw_module)) { + Result = ParseModuleDecl(); + return false; + } else if (getLangOpts().getCompilingModule() == + LangOptions::CMK_ModuleInterface) { + // FIXME: We avoid providing this diagnostic when generating an object file + // from an existing PCM file. This is not a good way to detect this + // condition; we should provide a mechanism to indicate whether we've + // already parsed a declaration in this translation unit and avoid calling + // ParseFirstTopLevelDecl in that case. + if (Actions.TUKind == TU_Module) + Diag(Tok, diag::err_expected_module_interface_decl); + } + + // C11 6.9p1 says translation units must have at least one top-level + // declaration. C++ doesn't have this restriction. We also don't want to + // complain if we have a precompiled header, although technically if the PCH + // is empty we should still emit the (pedantic) diagnostic. + bool NoTopLevelDecls = ParseTopLevelDecl(Result); + if (NoTopLevelDecls && !Actions.getASTContext().getExternalSource() && + !getLangOpts().CPlusPlus) + Diag(diag::ext_empty_translation_unit); + + return NoTopLevelDecls; +} + /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the /// action tells us to. This returns true if the EOF was encountered. bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { @@ -553,6 +582,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { HandlePragmaUnused(); return false; + case tok::kw_import: + Result = ParseModuleImport(SourceLocation()); + return false; + case tok::annot_module_include: Actions.ActOnModuleInclude(Tok.getLocation(), reinterpret_cast<Module *>( @@ -590,7 +623,6 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); - MaybeParseMicrosoftAttributes(attrs); Result = ParseExternalDeclaration(attrs); return false; @@ -737,11 +769,17 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, : Sema::PCC_Namespace); cutOffParsing(); return nullptr; + case tok::kw_export: + if (getLangOpts().ModulesTS) { + SingleDecl = ParseExportDeclaration(); + break; + } + // This must be 'export template'. Parse it so we can diagnose our lack + // of support. case tok::kw_using: case tok::kw_namespace: case tok::kw_typedef: case tok::kw_template: - case tok::kw_export: // As in 'export template' case tok::kw_static_assert: case tok::kw__Static_assert: // A function definition cannot start with any of these keywords. @@ -802,6 +840,11 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, ParseMicrosoftIfExistsExternalDeclaration(); return nullptr; + case tok::kw_module: + Diag(Tok, diag::err_unexpected_module_decl); + SkipUntil(tok::semi); + return nullptr; + default: dont_know: // We can't tell whether this is a function-definition or declaration yet. @@ -853,11 +896,10 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) { Tok.is(tok::kw_try); // X() try { ... } } -/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or -/// a declaration. We can't tell which we have until we read up to the -/// compound-statement in function-definition. TemplateParams, if -/// non-NULL, provides the template parameters when we're parsing a -/// C++ template-declaration. +/// Parse either a function-definition or a declaration. We can't tell which +/// we have until we read up to the compound-statement in function-definition. +/// TemplateParams, if non-NULL, provides the template parameters when we're +/// parsing a C++ template-declaration. /// /// function-definition: [C99 6.9.1] /// decl-specs declarator declaration-list[opt] compound-statement @@ -873,6 +915,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, ParsingDeclSpec &DS, AccessSpecifier AS) { + MaybeParseMicrosoftAttributes(DS.getAttributes()); // Parse the common declaration-specifiers piece. ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level); @@ -891,6 +934,8 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, DS, AnonRecord); DS.complete(TheDecl); + if (getLangOpts().OpenCL) + Actions.setCurrentOpenCLExtensionForDecl(TheDecl); if (AnonRecord) { Decl* decls[] = {AnonRecord, TheDecl}; return Actions.BuildDeclaratorGroup(decls, /*TypeMayContainAuto=*/false); @@ -952,7 +997,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs, // parsing c constructs and re-enter objc container scope // afterwards. ObjCDeclContextSwitch ObjCDC(*this); - + return ParseDeclOrFunctionDefInternal(attrs, PDS, AS); } } @@ -1495,6 +1540,8 @@ Parser::TryAnnotateName(bool IsAddressOfOperand, NewEndLoc); if (NewType.isUsable()) Ty = NewType.get(); + else if (Tok.is(tok::eof)) // Nothing to do here, bail out... + return ANK_Error; } Tok.setKind(tok::annot_typename); @@ -1726,6 +1773,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext, NewEndLoc); if (NewType.isUsable()) Ty = NewType.get(); + else if (Tok.is(tok::eof)) // Nothing to do here, bail out... + return false; } // This is a typename. Replace the current token in-place with an @@ -1988,7 +2037,6 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() { while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); - MaybeParseMicrosoftAttributes(attrs); DeclGroupPtrTy Result = ParseExternalDeclaration(attrs); if (Result && !getCurScope()->getParent()) Actions.getASTConsumer().HandleTopLevelDecl(Result.get()); @@ -1996,51 +2044,122 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() { Braces.consumeClose(); } +/// Parse a C++ Modules TS module declaration, which appears at the beginning +/// of a module interface, module partition, or module implementation file. +/// +/// module-declaration: [Modules TS + P0273R0] +/// 'module' module-kind[opt] module-name attribute-specifier-seq[opt] ';' +/// module-kind: +/// 'implementation' +/// 'partition' +/// +/// Note that the module-kind values are context-sensitive keywords. +Parser::DeclGroupPtrTy Parser::ParseModuleDecl() { + assert(Tok.is(tok::kw_module) && getLangOpts().ModulesTS && + "should not be parsing a module declaration"); + SourceLocation ModuleLoc = ConsumeToken(); + + // Check for a module-kind. + Sema::ModuleDeclKind MDK = Sema::ModuleDeclKind::Module; + if (Tok.is(tok::identifier) && NextToken().is(tok::identifier)) { + if (Tok.getIdentifierInfo()->isStr("implementation")) + MDK = Sema::ModuleDeclKind::Implementation; + else if (Tok.getIdentifierInfo()->isStr("partition")) + MDK = Sema::ModuleDeclKind::Partition; + else { + Diag(Tok, diag::err_unexpected_module_kind) << Tok.getIdentifierInfo(); + SkipUntil(tok::semi); + return nullptr; + } + ConsumeToken(); + } + + SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; + if (ParseModuleName(ModuleLoc, Path, /*IsImport*/false)) + return nullptr; + + ParsedAttributesWithRange Attrs(AttrFactory); + MaybeParseCXX11Attributes(Attrs); + // We don't support any module attributes yet. + ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr); + + ExpectAndConsumeSemi(diag::err_module_expected_semi); + + return Actions.ActOnModuleDecl(ModuleLoc, MDK, Path); +} + +/// Parse a module import declaration. This is essentially the same for +/// Objective-C and the C++ Modules TS, except for the leading '@' (in ObjC) +/// and the trailing optional attributes (in C++). +/// +/// [ObjC] @import declaration: +/// '@' 'import' module-name ';' +/// [ModTS] module-import-declaration: +/// 'import' module-name attribute-specifier-seq[opt] ';' Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) { - assert(Tok.isObjCAtKeyword(tok::objc_import) && + assert((AtLoc.isInvalid() ? Tok.is(tok::kw_import) + : Tok.isObjCAtKeyword(tok::objc_import)) && "Improper start to module import"); SourceLocation ImportLoc = ConsumeToken(); + SourceLocation StartLoc = AtLoc.isInvalid() ? ImportLoc : AtLoc; SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; - + if (ParseModuleName(ImportLoc, Path, /*IsImport*/true)) + return nullptr; + + ParsedAttributesWithRange Attrs(AttrFactory); + MaybeParseCXX11Attributes(Attrs); + // We don't support any module import attributes yet. + ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_import_attr); + + if (PP.hadModuleLoaderFatalFailure()) { + // With a fatal failure in the module loader, we abort parsing. + cutOffParsing(); + return nullptr; + } + + DeclResult Import = Actions.ActOnModuleImport(StartLoc, ImportLoc, Path); + ExpectAndConsumeSemi(diag::err_module_expected_semi); + if (Import.isInvalid()) + return nullptr; + + return Actions.ConvertDeclToDeclGroup(Import.get()); +} + +/// Parse a C++ Modules TS / Objective-C module name (both forms use the same +/// grammar). +/// +/// module-name: +/// module-name-qualifier[opt] identifier +/// module-name-qualifier: +/// module-name-qualifier[opt] identifier '.' +bool Parser::ParseModuleName( + SourceLocation UseLoc, + SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path, + bool IsImport) { // Parse the module path. - do { + while (true) { if (!Tok.is(tok::identifier)) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteModuleImport(ImportLoc, Path); + Actions.CodeCompleteModuleImport(UseLoc, Path); cutOffParsing(); - return nullptr; + return true; } - Diag(Tok, diag::err_module_expected_ident); + Diag(Tok, diag::err_module_expected_ident) << IsImport; SkipUntil(tok::semi); - return nullptr; + return true; } // Record this part of the module path. Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation())); ConsumeToken(); - - if (Tok.is(tok::period)) { - ConsumeToken(); - continue; - } - - break; - } while (true); - if (PP.hadModuleLoaderFatalFailure()) { - // With a fatal failure in the module loader, we abort parsing. - cutOffParsing(); - return nullptr; - } - - DeclResult Import = Actions.ActOnModuleImport(AtLoc, ImportLoc, Path); - ExpectAndConsumeSemi(diag::err_module_expected_semi); - if (Import.isInvalid()) - return nullptr; + if (Tok.isNot(tok::period)) + return false; - return Actions.ConvertDeclToDeclGroup(Import.get()); + ConsumeToken(); + } } /// \brief Try recover parser when module annotation appears where it must not @@ -2051,19 +2170,35 @@ bool Parser::parseMisplacedModuleImport() { while (true) { switch (Tok.getKind()) { case tok::annot_module_end: + // If we recovered from a misplaced module begin, we expect to hit a + // misplaced module end too. Stay in the current context when this + // happens. + if (MisplacedModuleBeginCount) { + --MisplacedModuleBeginCount; + Actions.ActOnModuleEnd(Tok.getLocation(), + reinterpret_cast<Module *>( + Tok.getAnnotationValue())); + ConsumeToken(); + continue; + } // Inform caller that recovery failed, the error must be handled at upper - // level. + // level. This will generate the desired "missing '}' at end of module" + // diagnostics on the way out. return true; case tok::annot_module_begin: - Actions.diagnoseMisplacedModuleImport(reinterpret_cast<Module *>( - Tok.getAnnotationValue()), Tok.getLocation()); - return true; + // Recover by entering the module (Sema will diagnose). + Actions.ActOnModuleBegin(Tok.getLocation(), + reinterpret_cast<Module *>( + Tok.getAnnotationValue())); + ConsumeToken(); + ++MisplacedModuleBeginCount; + continue; case tok::annot_module_include: // Module import found where it should not be, for instance, inside a // namespace. Recover by importing the module. Actions.ActOnModuleInclude(Tok.getLocation(), reinterpret_cast<Module *>( - Tok.getAnnotationValue())); + Tok.getAnnotationValue())); ConsumeToken(); // If there is another module import, process it. continue; |