diff options
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/ParseAST.cpp | 9 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 24 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 258 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 178 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 182 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 636 | ||||
-rw-r--r-- | lib/Parse/ParseInit.cpp | 38 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 65 | ||||
-rw-r--r-- | lib/Parse/ParseOpenMP.cpp | 528 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.cpp | 225 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 149 | ||||
-rw-r--r-- | lib/Parse/ParseStmtAsm.cpp | 87 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 156 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 247 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 291 |
15 files changed, 2214 insertions, 859 deletions
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp index f7703b1bfd8a0..3efd893e499cd 100644 --- a/lib/Parse/ParseAST.cpp +++ b/lib/Parse/ParseAST.cpp @@ -1,9 +1,8 @@ //===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -23,6 +22,7 @@ #include "clang/Sema/SemaConsumer.h" #include "clang/Sema/TemplateInstCallback.h" #include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/TimeProfiler.h" #include <cstdio> #include <memory> @@ -151,6 +151,7 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { bool HaveLexer = S.getPreprocessor().getCurrentLexer(); if (HaveLexer) { + llvm::TimeTraceScope TimeScope("Frontend", StringRef("")); P.Initialize(); Parser::DeclGroupPtrTy ADecl; for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF; diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index fde3ce00f8302..a1abf8269c451 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -1,9 +1,8 @@ //===--- ParseCXXInlineMethods.cpp - C++ class inline methods parsing------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -110,7 +109,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef( // the tokens and store them for parsing at the end of the translation unit. if (getLangOpts().DelayedTemplateParsing && D.getFunctionDefinitionKind() == FDK_Definition && - !D.getDeclSpec().isConstexprSpecified() && + !D.getDeclSpec().hasConstexprSpecifier() && !(FnD && FnD->getAsFunction() && FnD->getAsFunction()->getReturnType()->getContainedAutoType()) && ((Actions.CurContext->isDependentContext() || @@ -324,7 +323,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // Parse the default argument from its saved token stream. Toks->push_back(Tok); // So that the current token doesn't get lost - PP.EnterTokenStream(*Toks, true); + PP.EnterTokenStream(*Toks, true, /*IsReinject*/ true); // Consume the previously-pushed token. ConsumeAnyToken(); @@ -397,7 +396,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // Parse the default argument from its saved token stream. Toks->push_back(Tok); // So that the current token doesn't get lost - PP.EnterTokenStream(*Toks, true); + PP.EnterTokenStream(*Toks, true, /*IsReinject*/true); // Consume the previously-pushed token. ConsumeAnyToken(); @@ -416,7 +415,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { Method = cast<CXXMethodDecl>(LM.Method); Sema::CXXThisScopeRAII ThisScope(Actions, Method->getParent(), - Method->getTypeQualifiers(), + Method->getMethodQualifiers(), getLangOpts().CPlusPlus11); // Parse the exception-specification. @@ -504,7 +503,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { // Append the current token at the end of the new token stream so that it // doesn't get lost. LM.Toks.push_back(Tok); - PP.EnterTokenStream(LM.Toks, true); + PP.EnterTokenStream(LM.Toks, true, /*IsReinject*/true); // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); @@ -618,7 +617,7 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { // Append the current token at the end of the new token stream so that it // doesn't get lost. MI.Toks.push_back(Tok); - PP.EnterTokenStream(MI.Toks, true); + PP.EnterTokenStream(MI.Toks, true, /*IsReinject*/true); // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); @@ -990,7 +989,8 @@ public: auto Buffer = llvm::make_unique<Token[]>(Toks.size()); std::copy(Toks.begin() + 1, Toks.end(), Buffer.get()); Buffer[Toks.size() - 1] = Self.Tok; - Self.PP.EnterTokenStream(std::move(Buffer), Toks.size(), true); + Self.PP.EnterTokenStream(std::move(Buffer), Toks.size(), true, + /*IsReinject*/ true); Self.Tok = Toks.front(); } @@ -1058,7 +1058,7 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks, case CIK_DefaultArgument: bool InvalidAsDeclaration = false; Result = TryParseParameterDeclarationClause( - &InvalidAsDeclaration, /*VersusTemplateArgument=*/true); + &InvalidAsDeclaration, /*VersusTemplateArg=*/true); // If this is an expression or a declaration with a missing // 'typename', assume it's not a declaration. if (Result == TPResult::Ambiguous && InvalidAsDeclaration) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 298a2bad56c60..73b4f50fda460 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1,9 +1,8 @@ //===--- ParseDecl.cpp - Declaration Parsing --------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -86,6 +85,23 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) { #undef CLANG_ATTR_LATE_PARSED_LIST } +/// Check if the a start and end source location expand to the same macro. +bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc, + SourceLocation EndLoc) { + if (!StartLoc.isMacroID() || !EndLoc.isMacroID()) + return false; + + SourceManager &SM = PP.getSourceManager(); + if (SM.getFileID(StartLoc) != SM.getFileID(EndLoc)) + return false; + + bool AttrStartIsInMacro = + Lexer::isAtStartOfMacroExpansion(StartLoc, SM, PP.getLangOpts()); + bool AttrEndIsInMacro = + Lexer::isAtEndOfMacroExpansion(EndLoc, SM, PP.getLangOpts()); + return AttrStartIsInMacro && AttrEndIsInMacro; +} + /// ParseGNUAttributes - Parse a non-empty attributes list. /// /// [GNU] attributes: @@ -134,7 +150,10 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); while (Tok.is(tok::kw___attribute)) { - ConsumeToken(); + SourceLocation AttrTokLoc = ConsumeToken(); + unsigned OldNumAttrs = attrs.size(); + unsigned OldNumLateAttrs = LateAttrs ? LateAttrs->size() : 0; + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "attribute")) { SkipUntil(tok::r_paren, StopAtSemi); // skip until ) or ; @@ -145,10 +164,10 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, return; } // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") )) - while (true) { - // Allow empty/non-empty attributes. ((__vector_size__(16),,,,)) - if (TryConsumeToken(tok::comma)) - continue; + do { + // Eat preceeding commas to allow __attribute__((,,,foo)) + while (TryConsumeToken(tok::comma)) + ; // Expect an identifier or declaration specifier (const, int, etc.) if (Tok.isAnnotation()) @@ -193,7 +212,7 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, Eof.startToken(); Eof.setLocation(Tok.getLocation()); LA->Toks.push_back(Eof); - } + } while (Tok.is(tok::comma)); if (ExpectAndConsume(tok::r_paren)) SkipUntil(tok::r_paren, StopAtSemi); @@ -202,6 +221,25 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, SkipUntil(tok::r_paren, StopAtSemi); if (endLoc) *endLoc = Loc; + + // If this was declared in a macro, attach the macro IdentifierInfo to the + // parsed attribute. + auto &SM = PP.getSourceManager(); + if (!SM.isWrittenInBuiltinFile(SM.getSpellingLoc(AttrTokLoc)) && + FindLocsWithCommonFileID(PP, AttrTokLoc, Loc)) { + CharSourceRange ExpansionRange = SM.getExpansionRange(AttrTokLoc); + StringRef FoundName = + Lexer::getSourceText(ExpansionRange, SM, PP.getLangOpts()); + IdentifierInfo *MacroII = PP.getIdentifierInfo(FoundName); + + for (unsigned i = OldNumAttrs; i < attrs.size(); ++i) + attrs[i].setMacroIdentifier(MacroII, ExpansionRange.getBegin()); + + if (LateAttrs) { + for (unsigned i = OldNumLateAttrs; i < LateAttrs->size(); ++i) + (*LateAttrs)[i]->MacroII = MacroII; + } + } } } @@ -223,6 +261,15 @@ static bool attributeHasVariadicIdentifierArg(const IdentifierInfo &II) { #undef CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST } +/// Determine whether the given attribute treats kw_this as an identifier. +static bool attributeTreatsKeywordThisAsIdentifier(const IdentifierInfo &II) { +#define CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST + return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrParserStringSwitches.inc" + .Default(false); +#undef CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST +} + /// Determine whether the given attribute parses a type argument. static bool attributeIsTypeArgAttr(const IdentifierInfo &II) { #define CLANG_ATTR_TYPE_ARG_LIST @@ -287,6 +334,12 @@ unsigned Parser::ParseAttributeArgsCommon( // Ignore the left paren location for now. ConsumeParen(); + bool ChangeKWThisToIdent = attributeTreatsKeywordThisAsIdentifier(*AttrName); + + // Interpret "kw_this" as an identifier if the attributed requests it. + if (ChangeKWThisToIdent && Tok.is(tok::kw_this)) + Tok.setKind(tok::identifier); + ArgsVector ArgExprs; if (Tok.is(tok::identifier)) { // If this attribute wants an 'identifier' argument, make it so. @@ -314,6 +367,10 @@ unsigned Parser::ParseAttributeArgsCommon( // Parse the non-empty comma-separated list of expressions. do { + // Interpret "kw_this" as an identifier if the attributed requests it. + if (ChangeKWThisToIdent && Tok.is(tok::kw_this)) + Tok.setKind(tok::identifier); + ExprResult ArgExpr; if (Tok.is(tok::identifier) && attributeHasVariadicIdentifierArg(*AttrName)) { @@ -1413,7 +1470,7 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, // Append the current token at the end of the new token stream so that it // doesn't get lost. LA.Toks.push_back(Tok); - PP.EnterTokenStream(LA.Toks, true); + PP.EnterTokenStream(LA.Toks, true, /*IsReinject=*/true); // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); @@ -1716,7 +1773,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context, /// [C++11] attribute-specifier-seq decl-specifier-seq[opt] /// init-declarator-list ';' ///[C90/C++]init-declarator-list ';' [TODO] -/// [OMP] threadprivate-directive [TODO] +/// [OMP] threadprivate-directive +/// [OMP] allocate-directive [TODO] /// /// for-range-declaration: [C++11 6.5p1: stmt.ranged] /// attribute-specifier-seq[opt] type-specifier-seq declarator @@ -2275,7 +2333,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( return nullptr; } - ExprResult Init(ParseInitializer()); + PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl); + ExprResult Init = ParseInitializer(); // If this is the only decl in (possibly) range based for statement, // our best guess is that the user meant ':' instead of '='. @@ -2313,25 +2372,27 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( InitializerScopeRAII InitScope(*this, D, ThisDecl); - llvm::function_ref<void()> ExprListCompleter; auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl); - auto ConstructorCompleter = [&, ThisVarDecl] { + auto RunSignatureHelp = [&]() { QualType PreferredType = Actions.ProduceConstructorSignatureHelp( getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(), ThisDecl->getLocation(), Exprs, T.getOpenLocation()); CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); + return PreferredType; + }; + auto SetPreferredType = [&] { + PreferredType.enterFunctionArgument(Tok.getLocation(), RunSignatureHelp); }; + + llvm::function_ref<void()> ExpressionStarts; if (ThisVarDecl) { // ParseExpressionList can sometimes succeed even when ThisDecl is not // VarDecl. This is an error and it is reported in a call to // Actions.ActOnInitializerError(). However, we call - // ProduceConstructorSignatureHelp only on VarDecls, falling back to - // default completer in other cases. - ExprListCompleter = ConstructorCompleter; + // ProduceConstructorSignatureHelp only on VarDecls. + ExpressionStarts = SetPreferredType; } - - if (ParseExpressionList(Exprs, CommaLocs, ExprListCompleter)) { + if (ParseExpressionList(Exprs, CommaLocs, ExpressionStarts)) { if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) { Actions.ProduceConstructorSignatureHelp( getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(), @@ -2420,14 +2481,15 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec); if (DS.isVirtualSpecified()) Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec); - if (DS.isExplicitSpecified()) + if (DS.hasExplicitSpecifier()) Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec); DS.ClearFunctionSpecs(); } - // Issue diagnostic and remove constexpr specfier if present. - if (DS.isConstexprSpecified() && DSC != DeclSpecContext::DSC_condition) { - Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr); + // Issue diagnostic and remove constexpr specifier if present. + if (DS.hasConstexprSpecifier() && DSC != DeclSpecContext::DSC_condition) { + Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr) + << (DS.getConstexprSpecifier() == CSK_consteval); DS.ClearConstexprSpec(); } } @@ -2499,6 +2561,11 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, return false; } + // Early exit as Sema has a dedicated missing_actual_pipe_type diagnostic + // for incomplete declarations such as `pipe p`. + if (getLangOpts().OpenCLCPlusPlus && DS.isTypeSpecPipe()) + return false; + if (getLangOpts().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_auto) { // Don't require a type specifier if we have the 'auto' storage class @@ -2627,6 +2694,9 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, case tok::semi: // This looks like a variable or function declaration. The type is // probably missing. We're done parsing decl-specifiers. + // But only if we are not in a function prototype scope. + if (getCurScope()->isFunctionPrototypeScope()) + break; if (SS) AnnotateScopeToken(*SS, /*IsNewAnnotation*/false); return false; @@ -2680,7 +2750,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // TODO: Could inject an invalid typedef decl in an enclosing scope to // avoid rippling error messages on subsequent uses of the same type, // could be useful if #include was forgotten. - return false; + return true; } /// Determine the declaration specifier context from the declarator @@ -2832,7 +2902,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, IdentifierInfo *Name = AfterScope.getIdentifierInfo(); Sema::NameClassification Classification = Actions.ClassifyName( getCurScope(), SS, Name, AfterScope.getLocation(), Next, - /*IsAddressOfOperand*/false); + /*IsAddressOfOperand=*/false, /*CCC=*/nullptr); switch (Classification.getKind()) { case Sema::NC_Error: SkipMalformedDecl(); @@ -2853,6 +2923,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, case Sema::NC_Expression: case Sema::NC_VarTemplate: case Sema::NC_FunctionTemplate: + case Sema::NC_UndeclaredTemplate: // Might be a redeclaration of a prior entity. break; } @@ -2943,6 +3014,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, const char *PrevSpec = nullptr; unsigned DiagID = 0; + // This value needs to be set to the location of the last token if the last + // token of the specifier is already consumed. + SourceLocation ConsumedEnd; + // HACK: MSVC doesn't consider _Atomic to be a keyword and its STL // implementation for VS2013 uses _Atomic as an identifier for one of the // classes in <atomic>. @@ -3114,7 +3189,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(), getCurScope(), &SS, false, false, nullptr, /*IsCtorOrDtorName=*/false, - /*WantNonTrivialSourceInfo=*/true, + /*WantNontrivialTypeSourceInfo=*/true, isClassTemplateDeductionContext(DSContext)); // If the referenced identifier is not a type, then this declspec is @@ -3323,7 +3398,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // type-name case tok::annot_template_id: { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); - if (TemplateId->Kind != TNK_Type_template) { + if (TemplateId->Kind != TNK_Type_template && + TemplateId->Kind != TNK_Undeclared_template) { // This template-id does not refer to a type name, so we're // done with the type-specifiers. goto DoneWithDeclSpec; @@ -3483,7 +3559,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.setFunctionSpecInline(Loc, PrevSpec, DiagID); break; case tok::kw_virtual: - // OpenCL C++ v1.0 s2.9: the virtual function qualifier is not supported. + // C++ for OpenCL does not allow virtual function qualifier, to avoid + // function pointers restricted in OpenCL v2.0 s6.9.a. if (getLangOpts().OpenCLCPlusPlus) { DiagID = diag::err_openclcxx_virtual_function; PrevSpec = Tok.getIdentifierInfo()->getNameStart(); @@ -3493,9 +3570,33 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID); } break; - case tok::kw_explicit: - isInvalid = DS.setFunctionSpecExplicit(Loc, PrevSpec, DiagID); + case tok::kw_explicit: { + SourceLocation ExplicitLoc = Loc; + SourceLocation CloseParenLoc; + ExplicitSpecifier ExplicitSpec(nullptr, ExplicitSpecKind::ResolvedTrue); + ConsumedEnd = ExplicitLoc; + ConsumeToken(); // kw_explicit + if (Tok.is(tok::l_paren)) { + if (getLangOpts().CPlusPlus2a) { + ExprResult ExplicitExpr(static_cast<Expr *>(nullptr)); + BalancedDelimiterTracker Tracker(*this, tok::l_paren); + Tracker.consumeOpen(); + ExplicitExpr = ParseConstantExpression(); + ConsumedEnd = Tok.getLocation(); + if (ExplicitExpr.isUsable()) { + CloseParenLoc = Tok.getLocation(); + Tracker.consumeClose(); + ExplicitSpec = + Actions.ActOnExplicitBoolSpecifier(ExplicitExpr.get()); + } else + Tracker.skipToEnd(); + } else + Diag(Tok.getLocation(), diag::warn_cxx2a_compat_explicit_bool); + } + isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec, DiagID, + ExplicitSpec, CloseParenLoc); break; + } case tok::kw__Noreturn: if (!getLangOpts().C11) Diag(Loc, diag::ext_c11_noreturn); @@ -3527,7 +3628,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // constexpr case tok::kw_constexpr: - isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID); + isInvalid = DS.SetConstexprSpec(CSK_constexpr, Loc, PrevSpec, DiagID); + break; + + // consteval + case tok::kw_consteval: + isInvalid = DS.SetConstexprSpec(CSK_consteval, Loc, PrevSpec, DiagID); break; // type-specifier @@ -3675,7 +3781,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID, Policy); break; case tok::kw_pipe: - if (!getLangOpts().OpenCL || (getLangOpts().OpenCLVersion < 200)) { + if (!getLangOpts().OpenCL || (getLangOpts().OpenCLVersion < 200 && + !getLangOpts().OpenCLCPlusPlus)) { // OpenCL 2.0 defined this keyword. OpenCL 1.2 and earlier should // support the "pipe" word as identifier. Tok.getIdentifierInfo()->revertTokenIDToIdentifier(); @@ -3790,19 +3897,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, getLangOpts()); break; - // OpenCL access qualifiers: - case tok::kw___read_only: - case tok::kw___write_only: - case tok::kw___read_write: - // OpenCL C++ 1.0 s2.2: access qualifiers are reserved keywords. - if (Actions.getLangOpts().OpenCLCPlusPlus) { - DiagID = diag::err_openclcxx_reserved; - PrevSpec = Tok.getIdentifierInfo()->getNameStart(); - isInvalid = true; - } - ParseOpenCLQualifiers(DS.getAttributes()); - break; - // OpenCL address space qualifiers: case tok::kw___generic: // generic address space is introduced only in OpenCL v2.0 @@ -3815,10 +3909,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, break; }; LLVM_FALLTHROUGH; + case tok::kw_private: case tok::kw___private: case tok::kw___global: case tok::kw___local: case tok::kw___constant: + // OpenCL access qualifiers: + case tok::kw___read_only: + case tok::kw___write_only: + case tok::kw___read_write: ParseOpenCLQualifiers(DS.getAttributes()); break; @@ -3847,25 +3946,29 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // If a type specifier follows, it will be diagnosed elsewhere. continue; } + + DS.SetRangeEnd(ConsumedEnd.isValid() ? ConsumedEnd : Tok.getLocation()); + // If the specifier wasn't legal, issue a diagnostic. if (isInvalid) { assert(PrevSpec && "Method did not return previous specifier!"); assert(DiagID); if (DiagID == diag::ext_duplicate_declspec || - DiagID == diag::ext_warn_duplicate_declspec) - Diag(Tok, DiagID) - << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); + DiagID == diag::ext_warn_duplicate_declspec || + DiagID == diag::err_duplicate_declspec) + Diag(Loc, DiagID) << PrevSpec + << FixItHint::CreateRemoval( + SourceRange(Loc, DS.getEndLoc())); else if (DiagID == diag::err_opencl_unknown_type_specifier) { - Diag(Tok, DiagID) << getLangOpts().OpenCLCPlusPlus - << getLangOpts().getOpenCLVersionTuple().getAsString() - << PrevSpec << isStorageClass; + Diag(Loc, DiagID) << getLangOpts().OpenCLCPlusPlus + << getLangOpts().getOpenCLVersionTuple().getAsString() + << PrevSpec << isStorageClass; } else - Diag(Tok, DiagID) << PrevSpec; + Diag(Loc, DiagID) << PrevSpec; } - DS.SetRangeEnd(Tok.getLocation()); - if (DiagID != diag::err_bool_redeclaration) + if (DiagID != diag::err_bool_redeclaration && ConsumedEnd.isInvalid()) // After an error the next token can be an annotation token. ConsumeAnyToken(); @@ -3876,6 +3979,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, /// ParseStructDeclaration - Parse a struct declaration without the terminating /// semicolon. /// +/// Note that a struct declaration refers to a declaration in a struct, +/// not to the declaration of a struct. +/// /// struct-declaration: /// [C2x] attributes-specifier-seq[opt] /// specifier-qualifier-list struct-declarator-list @@ -4331,7 +4437,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (Tok.isNot(tok::semi)) { // A semicolon was missing after this declaration. Diagnose and recover. ExpectAndConsume(tok::semi, diag::err_expected_after, "enum"); - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject=*/true); Tok.setKind(tok::semi); } } else { @@ -4609,7 +4715,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { // Push this token back into the preprocessor and change our current token // to ';' so that the rest of the code recovers as though there were an // ';' after the definition. - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject=*/true); Tok.setKind(tok::semi); } } @@ -4782,9 +4888,11 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw___read_only: case tok::kw___read_write: case tok::kw___write_only: - return true; + case tok::kw_private: + return getLangOpts().OpenCL; + // C11 _Atomic case tok::kw__Atomic: return true; @@ -4801,7 +4909,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { default: return false; case tok::kw_pipe: - return getLangOpts().OpenCL && (getLangOpts().OpenCLVersion >= 200); + return (getLangOpts().OpenCL && getLangOpts().OpenCLVersion >= 200) || + getLangOpts().OpenCLCPlusPlus; case tok::identifier: // foo::bar // Unfortunate hack to support "Class.factoryMethod" notation. @@ -4929,6 +5038,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::annot_decltype: case tok::kw_constexpr: + // C++20 consteval. + case tok::kw_consteval: + // C11 _Atomic case tok::kw__Atomic: return true; @@ -4976,6 +5088,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { #include "clang/Basic/OpenCLImageTypes.def" return true; + + case tok::kw_private: + return getLangOpts().OpenCL; } } @@ -5176,6 +5291,10 @@ void Parser::ParseTypeQualifierListOpt( break; // OpenCL qualifiers: + case tok::kw_private: + if (!getLangOpts().OpenCL) + goto DoneWithTypeQuals; + LLVM_FALLTHROUGH; case tok::kw___private: case tok::kw___global: case tok::kw___local: @@ -5282,7 +5401,8 @@ static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang, if (Kind == tok::star || Kind == tok::caret) return true; - if ((Kind == tok::kw_pipe) && Lang.OpenCL && (Lang.OpenCLVersion >= 200)) + if (Kind == tok::kw_pipe && + ((Lang.OpenCL && Lang.OpenCLVersion >= 200) || Lang.OpenCLCPlusPlus)) return true; if (!Lang.CPlusPlus) @@ -6157,8 +6277,22 @@ void Parser::ParseFunctionDeclarator(Declarator &D, Actions.CurContext->isRecord()); Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers()); - if (D.getDeclSpec().isConstexprSpecified() && !getLangOpts().CPlusPlus14) + if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14) Q.addConst(); + // FIXME: Collect C++ address spaces. + // If there are multiple different address spaces, the source is invalid. + // Carry on using the first addr space for the qualifiers of 'this'. + // The diagnostic will be given later while creating the function + // prototype for the method. + if (getLangOpts().OpenCLCPlusPlus) { + for (ParsedAttr &attr : DS.getAttributes()) { + LangAS ASIdx = attr.asOpenCLLangAS(); + if (ASIdx != LangAS::Default) { + Q.addAddressSpace(ASIdx); + break; + } + } + } Sema::CXXThisScopeRAII ThisScope( Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), Q, diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index f8359f1e87d8e..9c61c4da447aa 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1,9 +1,8 @@ //===--- ParseDeclCXX.cpp - C++ Declaration Parsing -------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -25,6 +24,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/TimeProfiler.h" using namespace clang; @@ -437,9 +437,10 @@ Decl *Parser::ParseExportDeclaration() { // 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)) + if (Tok.is(tok::r_brace) && getLangOpts().ModulesTS) { Diag(ExportLoc, diag::err_export_empty) << SourceRange(ExportLoc, Tok.getLocation()); + } while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { @@ -473,6 +474,13 @@ Parser::ParseUsingDirectiveOrDeclaration(DeclaratorContext Context, return nullptr; } + // Consume unexpected 'template' keywords. + while (Tok.is(tok::kw_template)) { + SourceLocation TemplateLoc = ConsumeToken(); + Diag(TemplateLoc, diag::err_unexpected_template_after_using) + << FixItHint::CreateRemoval(TemplateLoc); + } + // 'using namespace' means this is a using-directive. if (Tok.is(tok::kw_namespace)) { // Template parameters are always an error here. @@ -589,10 +597,11 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context, // Parse nested-name-specifier. IdentifierInfo *LastII = nullptr; - ParseOptionalCXXScopeSpecifier(D.SS, nullptr, /*EnteringContext=*/false, - /*MayBePseudoDtor=*/nullptr, - /*IsTypename=*/false, - /*LastII=*/&LastII); + if (ParseOptionalCXXScopeSpecifier(D.SS, nullptr, /*EnteringContext=*/false, + /*MayBePseudoDtor=*/nullptr, + /*IsTypename=*/false, + /*LastII=*/&LastII)) + return true; if (D.SS.isInvalid()) return true; @@ -1031,7 +1040,7 @@ void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec& DS, if (PP.isBacktrackEnabled()) PP.RevertCachedTokens(1); else - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject*/true); Tok.setKind(tok::annot_decltype); setExprAnnotation(Tok, @@ -1103,7 +1112,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, // Parse optional nested-name-specifier CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); + if (ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false)) + return true; BaseLoc = Tok.getLocation(); @@ -1127,7 +1137,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind == TNK_Type_template || - TemplateId->Kind == TNK_Dependent_template_name) { + TemplateId->Kind == TNK_Dependent_template_name || + TemplateId->Kind == TNK_Undeclared_template) { AnnotateTemplateIdTokenAsType(/*IsClassName*/true); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); @@ -1197,9 +1208,9 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, // We have an identifier; check whether it is actually a type. IdentifierInfo *CorrectedII = nullptr; ParsedType Type = Actions.getTypeName( - *Id, IdLoc, getCurScope(), &SS, /*IsClassName=*/true, false, nullptr, + *Id, IdLoc, getCurScope(), &SS, /*isClassName=*/true, false, nullptr, /*IsCtorOrDtorName=*/false, - /*NonTrivialTypeSourceInfo=*/true, + /*WantNontrivialTypeSourceInfo=*/true, /*IsClassTemplateDeductionContext*/ false, &CorrectedII); if (!Type) { Diag(IdLoc, diag::err_expected_class_name); @@ -1248,9 +1259,11 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { case tok::ampamp: // struct foo {...} && R = ... case tok::identifier: // struct foo {...} V ; case tok::r_paren: //(struct foo {...} ) {4} + case tok::coloncolon: // struct foo {...} :: a::b; case tok::annot_cxxscope: // struct foo {...} a:: b; case tok::annot_typename: // struct foo {...} a ::b; case tok::annot_template_id: // struct foo {...} a<int> ::b; + case tok::kw_decltype: // struct foo {...} decltype (a)::b; case tok::l_paren: // struct foo {...} ( x); case tok::comma: // __builtin_offsetof(struct foo{...} , case tok::kw_operator: // struct foo operator ++() {...} @@ -1544,6 +1557,36 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; + auto RecoverFromUndeclaredTemplateName = [&](IdentifierInfo *Name, + SourceLocation NameLoc, + SourceRange TemplateArgRange, + bool KnownUndeclared) { + Diag(NameLoc, diag::err_explicit_spec_non_template) + << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + << TagTokKind << Name << TemplateArgRange << KnownUndeclared; + + // Strip off the last template parameter list if it was empty, since + // we've removed its template argument list. + if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) { + if (TemplateParams->size() > 1) { + TemplateParams->pop_back(); + } else { + TemplateParams = nullptr; + const_cast<ParsedTemplateInfo &>(TemplateInfo).Kind = + ParsedTemplateInfo::NonTemplate; + } + } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { + // Pretend this is just a forward declaration. + TemplateParams = nullptr; + const_cast<ParsedTemplateInfo &>(TemplateInfo).Kind = + ParsedTemplateInfo::NonTemplate; + const_cast<ParsedTemplateInfo &>(TemplateInfo).TemplateLoc = + SourceLocation(); + const_cast<ParsedTemplateInfo &>(TemplateInfo).ExternLoc = + SourceLocation(); + } + }; + // Parse the (optional) class name or simple-template-id. IdentifierInfo *Name = nullptr; SourceLocation NameLoc; @@ -1564,38 +1607,26 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // try to give any location information for the list. LAngleLoc = RAngleLoc = SourceLocation(); } - - Diag(NameLoc, diag::err_explicit_spec_non_template) - << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) - << TagTokKind << Name << SourceRange(LAngleLoc, RAngleLoc); - - // Strip off the last template parameter list if it was empty, since - // we've removed its template argument list. - if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) { - if (TemplateParams->size() > 1) { - TemplateParams->pop_back(); - } else { - TemplateParams = nullptr; - const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind - = ParsedTemplateInfo::NonTemplate; - } - } else if (TemplateInfo.Kind - == ParsedTemplateInfo::ExplicitInstantiation) { - // Pretend this is just a forward declaration. - TemplateParams = nullptr; - const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind - = ParsedTemplateInfo::NonTemplate; - const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc - = SourceLocation(); - const_cast<ParsedTemplateInfo&>(TemplateInfo).ExternLoc - = SourceLocation(); - } + RecoverFromUndeclaredTemplateName( + Name, NameLoc, SourceRange(LAngleLoc, RAngleLoc), false); } } else if (Tok.is(tok::annot_template_id)) { TemplateId = takeTemplateIdAnnotation(Tok); NameLoc = ConsumeAnnotationToken(); - if (TemplateId->Kind != TNK_Type_template && + if (TemplateId->Kind == TNK_Undeclared_template) { + // Try to resolve the template name to a type template. + Actions.ActOnUndeclaredTypeTemplateName(getCurScope(), TemplateId->Template, + TemplateId->Kind, NameLoc, Name); + if (TemplateId->Kind == TNK_Undeclared_template) { + RecoverFromUndeclaredTemplateName( + Name, NameLoc, + SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc), true); + TemplateId = nullptr; + } + } + + if (TemplateId && TemplateId->Kind != TNK_Type_template && TemplateId->Kind != TNK_Dependent_template_name) { // The template-name in the simple-template-id refers to // something other than a class template. Give an appropriate @@ -1606,7 +1637,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // FIXME: Name may be null here. Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template) - << TemplateId->Name << static_cast<int>(TemplateId->Kind) << Range; + << TemplateId->Name << static_cast<int>(TemplateId->Kind) << Range; DS.SetTypeSpecError(); SkipUntil(tok::semi, StopBeforeMatch); @@ -1705,7 +1736,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // A semicolon was missing after this declaration. Diagnose and recover. ExpectAndConsume(tok::semi, diag::err_expected_after, DeclSpec::getSpecifierName(TagType, PPol)); - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject*/true); Tok.setKind(tok::semi); } } else @@ -1982,7 +2013,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Push this token back into the preprocessor and change our current token // to ';' so that the rest of the code recovers as though there were an // ';' after the definition. - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject=*/true); Tok.setKind(tok::semi); } } @@ -2539,6 +2570,13 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Eat 'using'. SourceLocation UsingLoc = ConsumeToken(); + // Consume unexpected 'template' keywords. + while (Tok.is(tok::kw_template)) { + SourceLocation TemplateLoc = ConsumeToken(); + Diag(TemplateLoc, diag::err_unexpected_template_after_using) + << FixItHint::CreateRemoval(TemplateLoc); + } + if (Tok.is(tok::kw_namespace)) { Diag(UsingLoc, diag::err_using_namespace_in_class); SkipUntil(tok::semi, StopBeforeMatch); @@ -3048,9 +3086,14 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl)); return nullptr; + case tok::kw_private: + // FIXME: We don't accept GNU attributes on access specifiers in OpenCL mode + // yet. + if (getLangOpts().OpenCL && !NextToken().is(tok::colon)) + return ParseCXXClassMemberDeclaration(AS, AccessAttrs); + LLVM_FALLTHROUGH; case tok::kw_public: - case tok::kw_protected: - case tok::kw_private: { + case tok::kw_protected: { AccessSpecifier NewAS = getAccessSpecifierIfPresent(); assert(NewAS != AS_none); // Current token is a C++ access specifier. @@ -3110,6 +3153,12 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, TagType == DeclSpec::TST_union || TagType == DeclSpec::TST_class) && "Invalid TagType!"); + llvm::TimeTraceScope TimeScope("ParseClass", [&]() { + if (auto *TD = dyn_cast_or_null<NamedDecl>(TagDecl)) + return TD->getQualifiedNameAsString(); + return std::string("<anonymous>"); + }); + PrettyDeclStackTraceEntry CrashInfo(Actions.Context, TagDecl, RecordLoc, "parsing struct/union/class body"); @@ -3231,7 +3280,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (SuggestFixIt) { LBraceDiag << FixItHint::CreateInsertion(BraceLoc, " {"); // Try recovering from missing { after base-clause. - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject*/true); Tok.setKind(tok::l_brace); } else { if (TagDecl) @@ -3327,12 +3376,12 @@ void Parser::DiagnoseUnexpectedNamespace(NamedDecl *D) { diag::note_missing_end_of_definition_before) << D; // Push '};' onto the token stream to recover. - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject*/ true); Tok.startToken(); Tok.setLocation(PP.getLocForEndOfToken(PrevTokLocation)); Tok.setKind(tok::semi); - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject*/ true); Tok.setKind(tok::r_brace); } @@ -3423,7 +3472,8 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { // parse '::'[opt] nested-name-specifier[opt] CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); + if (ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false)) + return true; // : identifier IdentifierInfo *II = nullptr; @@ -3449,11 +3499,14 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { ? takeTemplateIdAnnotation(Tok) : nullptr; if (TemplateId && (TemplateId->Kind == TNK_Type_template || - TemplateId->Kind == TNK_Dependent_template_name)) { + TemplateId->Kind == TNK_Dependent_template_name || + TemplateId->Kind == TNK_Undeclared_template)) { AnnotateTemplateIdTokenAsType(/*IsClassName*/true); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); TemplateTypeTy = getTypeAnnotation(Tok); ConsumeAnnotationToken(); + if (!TemplateTypeTy) + return true; } else { Diag(Tok, diag::err_expected_member_or_base_name); return true; @@ -3482,20 +3535,20 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { // Parse the optional expression-list. ExprVector ArgExprs; CommaLocsTy CommaLocs; + auto RunSignatureHelp = [&] { + QualType PreferredType = Actions.ProduceCtorInitMemberSignatureHelp( + getCurScope(), ConstructorDecl, SS, TemplateTypeTy, ArgExprs, II, + T.getOpenLocation()); + CalledSignatureHelp = true; + return PreferredType; + }; if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs, [&] { - QualType PreferredType = Actions.ProduceCtorInitMemberSignatureHelp( - getCurScope(), ConstructorDecl, SS, TemplateTypeTy, ArgExprs, II, - T.getOpenLocation()); - CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); + PreferredType.enterFunctionArgument(Tok.getLocation(), + RunSignatureHelp); })) { - if (PP.isCodeCompletionReached() && !CalledSignatureHelp) { - Actions.ProduceCtorInitMemberSignatureHelp( - getCurScope(), ConstructorDecl, SS, TemplateTypeTy, ArgExprs, II, - T.getOpenLocation()); - CalledSignatureHelp = true; - } + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) + RunSignatureHelp(); SkipUntil(tok::r_paren, StopAtSemi); return true; } @@ -3859,6 +3912,7 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName, case ParsedAttr::AT_Deprecated: case ParsedAttr::AT_FallThrough: case ParsedAttr::AT_CXX11NoReturn: + case ParsedAttr::AT_NoUniqueAddress: return true; case ParsedAttr::AT_WarnUnusedResult: return !ScopeName && AttrName->getName().equals("nodiscard"); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 4bcbebcbb48ec..7a0c07bd3b04e 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1,9 +1,8 @@ //===--- ParseExpr.cpp - Expression Parsing -------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// @@ -159,7 +158,8 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { /// Parse an expr that doesn't include (top-level) commas. ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); + Actions.CodeCompleteExpression(getCurScope(), + PreferredType.get(Tok.getLocation())); cutOffParsing(); return ExprError(); } @@ -272,7 +272,10 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { getLangOpts().CPlusPlus11); SourceLocation ColonLoc; + auto SavedType = PreferredType; while (1) { + // Every iteration may rely on a preferred type for the whole expression. + PreferredType = SavedType; // If this token has a lower precedence than we are allowed to parse (e.g. // because we are called recursively, or because the token is not a binop), // then we are done! @@ -300,7 +303,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { // We can't do this before consuming the comma, because // isNotExpressionStart() looks at the token stream. if (OpToken.is(tok::comma) && isNotExpressionStart()) { - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject*/true); Tok = OpToken; return LHS; } @@ -310,7 +313,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { if (isFoldOperator(NextTokPrec) && Tok.is(tok::ellipsis)) { // FIXME: We can't check this via lookahead before we consume the token // because that tickles a lexer bug. - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject*/true); Tok = OpToken; return LHS; } @@ -323,7 +326,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { if (getLangOpts().ObjC && getLangOpts().CPlusPlus && Tok.isOneOf(tok::colon, tok::r_square) && OpToken.getIdentifierInfo() != nullptr) { - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject*/true); Tok = OpToken; return LHS; } @@ -393,15 +396,8 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { } } - // Code completion for the right-hand side of a binary expression goes - // through a special hook that takes the left-hand side into account. - if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteBinaryRHS(getCurScope(), LHS.get(), - OpToken.getKind()); - cutOffParsing(); - return ExprError(); - } - + PreferredType.enterBinary(Actions, Tok.getLocation(), LHS.get(), + OpToken.getKind()); // Parse another leaf here for the RHS of the operator. // ParseCastExpression works here because all RHS expressions in C have it // as a prefix, at least. However, in C++, an assignment-expression could @@ -547,7 +543,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, } namespace { -class CastExpressionIdValidator : public CorrectionCandidateCallback { +class CastExpressionIdValidator final : public CorrectionCandidateCallback { public: CastExpressionIdValidator(Token Next, bool AllowTypes, bool AllowNonTypes) : NextToken(Next), AllowNonTypes(AllowNonTypes) { @@ -576,6 +572,10 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { return false; } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<CastExpressionIdValidator>(*this); + } + private: Token NextToken; bool AllowNonTypes; @@ -639,6 +639,10 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { /// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' +/// [GNU] '__builtin_FILE' '(' ')' +/// [GNU] '__builtin_FUNCTION' '(' ')' +/// [GNU] '__builtin_LINE' '(' ')' +/// [CLANG] '__builtin_COLUMN' '(' ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' /// [GNU] '__null' /// [OBJC] '[' objc-message-expr ']' @@ -764,6 +768,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isVectorLiteral) { ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); + auto SavedType = PreferredType; NotCastExpr = false; // This handles all of cast-expression, unary-expression, postfix-expression, @@ -1044,19 +1049,21 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, CXXScopeSpec ScopeSpec; SourceLocation TemplateKWLoc; Token Replacement; - auto Validator = llvm::make_unique<CastExpressionIdValidator>( - Tok, isTypeCast != NotTypeCast, isTypeCast != IsTypeCast); - Validator->IsAddressOfOperand = isAddressOfOperand; + CastExpressionIdValidator Validator( + /*Next=*/Tok, + /*AllowTypes=*/isTypeCast != NotTypeCast, + /*AllowNonTypes=*/isTypeCast != IsTypeCast); + Validator.IsAddressOfOperand = isAddressOfOperand; if (Tok.isOneOf(tok::periodstar, tok::arrowstar)) { - Validator->WantExpressionKeywords = false; - Validator->WantRemainingKeywords = false; + Validator.WantExpressionKeywords = false; + Validator.WantRemainingKeywords = false; } else { - Validator->WantRemainingKeywords = Tok.isNot(tok::r_paren); + Validator.WantRemainingKeywords = Tok.isNot(tok::r_paren); } Name.setIdentifier(&II, ILoc); Res = Actions.ActOnIdExpression( getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren), - isAddressOfOperand, std::move(Validator), + isAddressOfOperand, &Validator, /*IsInlineAsmIdentifier=*/false, Tok.is(tok::r_paren) ? nullptr : &Replacement); if (!Res.isInvalid() && Res.isUnset()) { @@ -1103,6 +1110,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___builtin_choose_expr: case tok::kw___builtin_astype: // primary-expression: [OCL] as_type() case tok::kw___builtin_convertvector: + case tok::kw___builtin_COLUMN: + case tok::kw___builtin_FILE: + case tok::kw___builtin_FUNCTION: + case tok::kw___builtin_LINE: return ParseBuiltinPrimaryExpression(); case tok::kw___null: return Actions.ActOnGNUNullExpr(ConsumeToken()); @@ -1115,6 +1126,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // -- cast-expression Token SavedTok = Tok; ConsumeToken(); + + PreferredType.enterUnary(Actions, Tok.getLocation(), SavedTok.getKind(), + SavedTok.getLocation()); // One special case is implicitly handled here: if the preceding tokens are // an ambiguous cast expression, such as "(T())++", then we recurse to // determine whether the '++' is prefix or postfix. @@ -1136,6 +1150,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::amp: { // unary-expression: '&' cast-expression // Special treatment because of member pointers SourceLocation SavedLoc = ConsumeToken(); + PreferredType.enterUnary(Actions, Tok.getLocation(), tok::amp, SavedLoc); Res = ParseCastExpression(false, true); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); @@ -1150,6 +1165,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___real: // unary-expression: '__real' cast-expression [GNU] case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU] SourceLocation SavedLoc = ConsumeToken(); + PreferredType.enterUnary(Actions, Tok.getLocation(), SavedKind, SavedLoc); Res = ParseCastExpression(false); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); @@ -1207,6 +1223,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_static_cast: Res = ParseCXXCasts(); break; + case tok::kw___builtin_bit_cast: + Res = ParseBuiltinBitCast(); + break; case tok::kw_typeid: Res = ParseCXXTypeid(); break; @@ -1424,7 +1443,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = ParseBlockLiteralExpression(); break; case tok::code_completion: { - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); + Actions.CodeCompleteExpression(getCurScope(), + PreferredType.get(Tok.getLocation())); cutOffParsing(); return ExprError(); } @@ -1459,6 +1479,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // that the address of the function is being taken, which is illegal in CL. // These can be followed by postfix-expr pieces. + PreferredType = SavedType; Res = ParsePostfixExpressionSuffix(Res); if (getLangOpts().OpenCL) if (Expr *PostfixExpr = Res.get()) { @@ -1498,13 +1519,17 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Now that the primary-expression piece of the postfix-expression has been // parsed, see if there are any postfix-expression pieces here. SourceLocation Loc; + auto SavedType = PreferredType; while (1) { + // Each iteration relies on preferred type for the whole expression. + PreferredType = SavedType; switch (Tok.getKind()) { case tok::code_completion: if (InMessageExpression) return LHS; - Actions.CodeCompletePostfixExpression(getCurScope(), LHS); + Actions.CodeCompletePostfixExpression( + getCurScope(), LHS, PreferredType.get(Tok.getLocation())); cutOffParsing(); return ExprError(); @@ -1546,6 +1571,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { Loc = T.getOpenLocation(); ExprResult Idx, Length; SourceLocation ColonLoc; + PreferredType.enterSubscript(Actions, Tok.getLocation(), LHS.get()); if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Idx = ParseBraceInitializer(); @@ -1567,7 +1593,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { SourceLocation RLoc = Tok.getLocation(); - ExprResult OrigLHS = LHS; + LHS = Actions.CorrectDelayedTyposInExpr(LHS); + Idx = Actions.CorrectDelayedTyposInExpr(Idx); + Length = Actions.CorrectDelayedTyposInExpr(Length); if (!LHS.isInvalid() && !Idx.isInvalid() && !Length.isInvalid() && Tok.is(tok::r_square)) { if (ColonLoc.isValid()) { @@ -1579,12 +1607,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } } else { LHS = ExprError(); - } - if (LHS.isInvalid()) { - (void)Actions.CorrectDelayedTyposInExpr(OrigLHS); - (void)Actions.CorrectDelayedTyposInExpr(Idx); - (void)Actions.CorrectDelayedTyposInExpr(Length); - LHS = ExprError(); Idx = ExprError(); } @@ -1649,34 +1671,25 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { ExprVector ArgExprs; CommaLocsTy CommaLocs; - - if (Tok.is(tok::code_completion)) { + auto RunSignatureHelp = [&]() -> QualType { QualType PreferredType = Actions.ProduceCallSignatureHelp( - getCurScope(), LHS.get(), None, PT.getOpenLocation()); + getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation()); CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); - cutOffParsing(); - return ExprError(); - } - + return PreferredType; + }; if (OpKind == tok::l_paren || !LHS.isInvalid()) { if (Tok.isNot(tok::r_paren)) { if (ParseExpressionList(ArgExprs, CommaLocs, [&] { - QualType PreferredType = Actions.ProduceCallSignatureHelp( - getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation()); - CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); + PreferredType.enterFunctionArgument(Tok.getLocation(), + RunSignatureHelp); })) { (void)Actions.CorrectDelayedTyposInExpr(LHS); // If we got an error when parsing expression list, we don't call // the CodeCompleteCall handler inside the parser. So call it here // to make sure we get overload suggestions even when we are in the // middle of a parameter. - if (PP.isCodeCompletionReached() && !CalledSignatureHelp) { - Actions.ProduceCallSignatureHelp(getCurScope(), LHS.get(), - ArgExprs, PT.getOpenLocation()); - CalledSignatureHelp = true; - } + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) + RunSignatureHelp(); LHS = ExprError(); } else if (LHS.isInvalid()) { for (auto &E : ArgExprs) @@ -1727,6 +1740,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { bool MayBePseudoDestructor = false; Expr* OrigLHS = !LHS.isInvalid() ? LHS.get() : nullptr; + PreferredType.enterMemAccess(Actions, Tok.getLocation(), OrigLHS); + if (getLangOpts().CPlusPlus && !LHS.isInvalid()) { Expr *Base = OrigLHS; const Type* BaseType = Base->getType().getTypePtrOrNull(); @@ -1755,7 +1770,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (Tok.is(tok::code_completion)) { tok::TokenKind CorrectedOpKind = OpKind == tok::arrow ? tok::period : tok::arrow; - ExprResult CorrectedLHS(/*IsInvalid=*/true); + ExprResult CorrectedLHS(/*Invalid=*/true); if (getLangOpts().CPlusPlus && OrigLHS) { const bool DiagsAreSuppressed = Diags.getSuppressAllDiagnostics(); Diags.setSuppressAllDiagnostics(true); @@ -1773,7 +1788,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Code completion for a member access expression. Actions.CodeCompleteMemberReferenceExpr( getCurScope(), Base, CorrectedBase, OpLoc, OpKind == tok::arrow, - Base && ExprStatementTokLoc == Base->getBeginLoc()); + Base && ExprStatementTokLoc == Base->getBeginLoc(), + PreferredType.get(Tok.getLocation())); cutOffParsing(); return ExprError(); @@ -2036,7 +2052,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { if (isCastExpr) return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), ExprKind, - /*isType=*/true, + /*IsType=*/true, CastTy.getAsOpaquePtr(), CastRange); @@ -2047,7 +2063,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { if (!Operand.isInvalid()) Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), ExprKind, - /*isType=*/false, + /*IsType=*/false, Operand.get(), CastRange); return Operand; @@ -2062,6 +2078,10 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' +/// [GNU] '__builtin_FILE' '(' ')' +/// [GNU] '__builtin_FUNCTION' '(' ')' +/// [GNU] '__builtin_LINE' '(' ')' +/// [CLANG] '__builtin_COLUMN' '(' ')' /// [OCL] '__builtin_astype' '(' assignment-expression ',' type-name ')' /// /// [GNU] offsetof-member-designator: @@ -2281,6 +2301,33 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { ConsumeParen()); break; } + case tok::kw___builtin_COLUMN: + case tok::kw___builtin_FILE: + case tok::kw___builtin_FUNCTION: + case tok::kw___builtin_LINE: { + // Attempt to consume the r-paren. + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected) << tok::r_paren; + SkipUntil(tok::r_paren, StopAtSemi); + return ExprError(); + } + SourceLocExpr::IdentKind Kind = [&] { + switch (T) { + case tok::kw___builtin_FILE: + return SourceLocExpr::File; + case tok::kw___builtin_FUNCTION: + return SourceLocExpr::Function; + case tok::kw___builtin_LINE: + return SourceLocExpr::Line; + case tok::kw___builtin_COLUMN: + return SourceLocExpr::Column; + default: + llvm_unreachable("invalid keyword"); + } + }(); + Res = Actions.ActOnSourceLocExpr(Kind, StartLoc, ConsumeParen()); + break; + } } if (Res.isInvalid()) @@ -2327,14 +2374,16 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, return ExprError(); SourceLocation OpenLoc = T.getOpenLocation(); + PreferredType.enterParenExpr(Tok.getLocation(), OpenLoc); + ExprResult Result(true); bool isAmbiguousTypeId; CastTy = nullptr; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(getCurScope(), - ExprType >= CompoundLiteral? Sema::PCC_ParenthesizedExpression - : Sema::PCC_Expression); + Actions.CodeCompleteExpression( + getCurScope(), PreferredType.get(Tok.getLocation()), + /*IsParenthesized=*/ExprType >= CompoundLiteral); cutOffParsing(); return ExprError(); } @@ -2415,6 +2464,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, T.consumeClose(); ColonProtection.restore(); RParenLoc = T.getCloseLocation(); + + PreferredType.enterTypeCast(Tok.getLocation(), Ty.get().get()); ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false); if (Ty.isInvalid() || SubExpr.isInvalid()) @@ -2545,6 +2596,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, return ExprError(); } + PreferredType.enterTypeCast(Tok.getLocation(), CastTy.get()); // Parse the cast-expression that follows it next. // TODO: For cast expression with CastTy. Result = ParseCastExpression(/*isUnaryExpression=*/false, @@ -2839,17 +2891,11 @@ ExprResult Parser::ParseFoldExpression(ExprResult LHS, /// \endverbatim bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, SmallVectorImpl<SourceLocation> &CommaLocs, - llvm::function_ref<void()> Completer) { + llvm::function_ref<void()> ExpressionStarts) { bool SawError = false; while (1) { - if (Tok.is(tok::code_completion)) { - if (Completer) - Completer(); - else - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); - cutOffParsing(); - return true; - } + if (ExpressionStarts) + ExpressionStarts(); ExprResult Expr; if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { @@ -3009,7 +3055,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { /*IsAmbiguous=*/false, /*RParenLoc=*/NoLoc, /*ArgInfo=*/nullptr, - /*NumArgs=*/0, + /*NumParams=*/0, /*EllipsisLoc=*/NoLoc, /*RParenLoc=*/NoLoc, /*RefQualifierIsLvalueRef=*/true, diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 3caec6b4def6e..85c7e6c6bcdf9 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1,9 +1,8 @@ //===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -21,7 +20,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "llvm/Support/ErrorHandling.h" - +#include <numeric> using namespace clang; @@ -70,9 +69,9 @@ static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken, DigraphToken.setLength(1); // Push new tokens back to token stream. - PP.EnterToken(ColonToken); + PP.EnterToken(ColonToken, /*IsReinject*/ true); if (!AtDigraph) - PP.EnterToken(DigraphToken); + PP.EnterToken(DigraphToken, /*IsReinject*/ true); } // Check for '<::' which should be '< ::' instead of '[:' when following @@ -233,13 +232,16 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, HasScopeSpecifier = true; } + // Preferred type might change when parsing qualifiers, we need the original. + auto SavedType = PreferredType; while (true) { if (HasScopeSpecifier) { if (Tok.is(tok::code_completion)) { // Code completion for a nested-name-specifier, where the code // completion token follows the '::'. Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext, - ObjectType.get()); + ObjectType.get(), + SavedType.get(SS.getBeginLoc())); // Include code completion token into the range of the scope otherwise // when we try to annotate the scope tokens the dangling code completion // token will cause assertion in @@ -435,7 +437,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, Token ColonColon; PP.Lex(ColonColon); ColonColon.setKind(tok::colon); - PP.EnterToken(ColonColon); + PP.EnterToken(ColonColon, /*IsReinject*/ true); break; } } @@ -461,8 +463,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // mistyped '::' instead of ':'. if (CorrectionFlagPtr && IsCorrectedToColon) { ColonColon.setKind(tok::colon); - PP.EnterToken(Tok); - PP.EnterToken(ColonColon); + PP.EnterToken(Tok, /*IsReinject*/ true); + PP.EnterToken(ColonColon, /*IsReinject*/ true); Tok = Identifier; break; } @@ -488,6 +490,14 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, EnteringContext, Template, MemberOfUnknownSpecialization)) { + // If lookup didn't find anything, we treat the name as a template-name + // anyway. C++20 requires this, and in prior language modes it improves + // error recovery. But before we commit to this, check that we actually + // have something that looks like a template-argument-list next. + if (!IsTypename && TNK == TNK_Undeclared_template && + isTemplateArgumentList(1) == TPResult::False) + break; + // We have found a template name, so annotate this token // with a template-id annotation. We do not permit the // template-id to be translated into a type annotation, @@ -502,7 +512,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, } if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && - (IsTypename || IsTemplateArgumentList(1))) { + (IsTypename || isTemplateArgumentList(1) == TPResult::True)) { // We have something like t::getAs<T>, where getAs is a // member of an unknown specialization. However, this will only // parse correctly as a template, so suggest the keyword 'template' @@ -564,7 +574,7 @@ ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOpe ExprResult E = Actions.ActOnIdExpression( getCurScope(), SS, TemplateKWLoc, Name, Tok.is(tok::l_paren), - isAddressOfOperand, nullptr, /*IsInlineAsmIdentifier=*/false, + isAddressOfOperand, /*CCC=*/nullptr, /*IsInlineAsmIdentifier=*/false, &Replacement); if (!E.isInvalid() && !E.isUnset() && Tok.is(tok::less)) checkPotentialAngleBracket(E); @@ -639,6 +649,8 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { /// /// lambda-expression: /// lambda-introducer lambda-declarator[opt] compound-statement +/// lambda-introducer '<' template-parameter-list '>' +/// lambda-declarator[opt] compound-statement /// /// lambda-introducer: /// '[' lambda-capture[opt] ']' @@ -677,9 +689,7 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { ExprResult Parser::ParseLambdaExpression() { // Parse lambda-introducer. LambdaIntroducer Intro; - Optional<unsigned> DiagID = ParseLambdaIntroducer(Intro); - if (DiagID) { - Diag(Tok, DiagID.getValue()); + if (ParseLambdaIntroducer(Intro)) { SkipUntil(tok::r_square, StopAtSemi); SkipUntil(tok::l_brace, StopAtSemi); SkipUntil(tok::r_brace, StopAtSemi); @@ -689,9 +699,8 @@ ExprResult Parser::ParseLambdaExpression() { return ParseLambdaExpressionAfterIntroducer(Intro); } -/// TryParseLambdaExpression - Use lookahead and potentially tentative -/// parsing to determine if we are looking at a C++0x lambda expression, and parse -/// it if we are. +/// Use lookahead and potentially tentative parsing to determine if we are +/// looking at a C++11 lambda expression, and parse it if we are. /// /// If we are not looking at a lambda expression, returns ExprError(). ExprResult Parser::TryParseLambdaExpression() { @@ -708,28 +717,53 @@ ExprResult Parser::TryParseLambdaExpression() { if (Next.is(tok::r_square) || // [] Next.is(tok::equal) || // [= (Next.is(tok::amp) && // [&] or [&, - (After.is(tok::r_square) || - After.is(tok::comma))) || + After.isOneOf(tok::r_square, tok::comma)) || (Next.is(tok::identifier) && // [identifier] - After.is(tok::r_square))) { + After.is(tok::r_square)) || + Next.is(tok::ellipsis)) { // [... return ParseLambdaExpression(); } // If lookahead indicates an ObjC message send... // [identifier identifier - if (Next.is(tok::identifier) && After.is(tok::identifier)) { + if (Next.is(tok::identifier) && After.is(tok::identifier)) return ExprEmpty(); - } // Here, we're stuck: lambda introducers and Objective-C message sends are // unambiguous, but it requires arbitrary lookhead. [a,b,c,d,e,f,g] is a // lambda, and [a,b,c,d,e,f,g h] is a Objective-C message send. Instead of // writing two routines to parse a lambda introducer, just try to parse // a lambda introducer first, and fall back if that fails. - // (TryParseLambdaIntroducer never produces any diagnostic output.) LambdaIntroducer Intro; - if (TryParseLambdaIntroducer(Intro)) - return ExprEmpty(); + { + TentativeParsingAction TPA(*this); + LambdaIntroducerTentativeParse Tentative; + if (ParseLambdaIntroducer(Intro, &Tentative)) { + TPA.Commit(); + return ExprError(); + } + + switch (Tentative) { + case LambdaIntroducerTentativeParse::Success: + TPA.Commit(); + break; + + case LambdaIntroducerTentativeParse::Incomplete: + // Didn't fully parse the lambda-introducer, try again with a + // non-tentative parse. + TPA.Revert(); + Intro = LambdaIntroducer(); + if (ParseLambdaIntroducer(Intro)) + return ExprError(); + break; + + case LambdaIntroducerTentativeParse::MessageSend: + case LambdaIntroducerTentativeParse::Invalid: + // Not a lambda-introducer, might be a message send. + TPA.Revert(); + return ExprEmpty(); + } + } return ParseLambdaExpressionAfterIntroducer(Intro); } @@ -737,15 +771,16 @@ ExprResult Parser::TryParseLambdaExpression() { /// Parse a lambda introducer. /// \param Intro A LambdaIntroducer filled in with information about the /// contents of the lambda-introducer. -/// \param SkippedInits If non-null, we are disambiguating between an Obj-C -/// message send and a lambda expression. In this mode, we will -/// sometimes skip the initializers for init-captures and not fully -/// populate \p Intro. This flag will be set to \c true if we do so. -/// \return A DiagnosticID if it hit something unexpected. The location for -/// the diagnostic is that of the current token. -Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, - bool *SkippedInits) { - typedef Optional<unsigned> DiagResult; +/// \param Tentative If non-null, we are disambiguating between a +/// lambda-introducer and some other construct. In this mode, we do not +/// produce any diagnostics or take any other irreversible action unless +/// we're sure that this is a lambda-expression. +/// \return \c true if parsing (or disambiguation) failed with a diagnostic and +/// the caller should bail out / recover. +bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, + LambdaIntroducerTentativeParse *Tentative) { + if (Tentative) + *Tentative = LambdaIntroducerTentativeParse::Success; assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['."); BalancedDelimiterTracker T(*this, tok::l_square); @@ -753,37 +788,64 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, Intro.Range.setBegin(T.getOpenLocation()); - bool first = true; + bool First = true; + + // Produce a diagnostic if we're not tentatively parsing; otherwise track + // that our parse has failed. + auto Invalid = [&](llvm::function_ref<void()> Action) { + if (Tentative) { + *Tentative = LambdaIntroducerTentativeParse::Invalid; + return false; + } + Action(); + return true; + }; + + // Perform some irreversible action if this is a non-tentative parse; + // otherwise note that our actions were incomplete. + auto NonTentativeAction = [&](llvm::function_ref<void()> Action) { + if (Tentative) + *Tentative = LambdaIntroducerTentativeParse::Incomplete; + else + Action(); + }; // Parse capture-default. if (Tok.is(tok::amp) && (NextToken().is(tok::comma) || NextToken().is(tok::r_square))) { Intro.Default = LCD_ByRef; Intro.DefaultLoc = ConsumeToken(); - first = false; + First = false; + if (!Tok.getIdentifierInfo()) { + // This can only be a lambda; no need for tentative parsing any more. + // '[[and]]' can still be an attribute, though. + Tentative = nullptr; + } } else if (Tok.is(tok::equal)) { Intro.Default = LCD_ByCopy; Intro.DefaultLoc = ConsumeToken(); - first = false; + First = false; + Tentative = nullptr; } while (Tok.isNot(tok::r_square)) { - if (!first) { + if (!First) { if (Tok.isNot(tok::comma)) { // Provide a completion for a lambda introducer here. Except // in Objective-C, where this is Almost Surely meant to be a message // send. In that case, fail here and let the ObjC message // expression parser perform the completion. if (Tok.is(tok::code_completion) && - !(getLangOpts().ObjC && Intro.Default == LCD_None && - !Intro.Captures.empty())) { + !(getLangOpts().ObjC && Tentative)) { Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, /*AfterAmpersand=*/false); cutOffParsing(); break; } - return DiagResult(diag::err_expected_comma_or_rsquare); + return Invalid([&] { + Diag(Tok.getLocation(), diag::err_expected_comma_or_rsquare); + }); } ConsumeToken(); } @@ -791,7 +853,7 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, if (Tok.is(tok::code_completion)) { // If we're in Objective-C++ and we have a bare '[', then this is more // likely to be a message receiver. - if (getLangOpts().ObjC && first) + if (getLangOpts().ObjC && Tentative && First) Actions.CodeCompleteObjCMessageReceiver(getCurScope()); else Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, @@ -800,14 +862,14 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, break; } - first = false; + First = false; // Parse capture. LambdaCaptureKind Kind = LCK_ByCopy; LambdaCaptureInitKind InitKind = LambdaCaptureInitKind::NoInit; SourceLocation Loc; IdentifierInfo *Id = nullptr; - SourceLocation EllipsisLoc; + SourceLocation EllipsisLocs[4]; ExprResult Init; SourceLocation LocStart = Tok.getLocation(); @@ -817,12 +879,16 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, ConsumeToken(); Kind = LCK_StarThis; } else { - return DiagResult(diag::err_expected_star_this_capture); + return Invalid([&] { + Diag(Tok.getLocation(), diag::err_expected_star_this_capture); + }); } } else if (Tok.is(tok::kw_this)) { Kind = LCK_This; Loc = ConsumeToken(); } else { + TryConsumeToken(tok::ellipsis, EllipsisLocs[0]); + if (Tok.is(tok::amp)) { Kind = LCK_ByRef; ConsumeToken(); @@ -835,18 +901,24 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, } } + TryConsumeToken(tok::ellipsis, EllipsisLocs[1]); + if (Tok.is(tok::identifier)) { Id = Tok.getIdentifierInfo(); Loc = ConsumeToken(); } else if (Tok.is(tok::kw_this)) { - // FIXME: If we want to suggest a fixit here, will need to return more - // than just DiagnosticID. Perhaps full DiagnosticBuilder that can be - // Clear()ed to prevent emission in case of tentative parsing? - return DiagResult(diag::err_this_captured_by_reference); + return Invalid([&] { + // FIXME: Suggest a fixit here. + Diag(Tok.getLocation(), diag::err_this_captured_by_reference); + }); } else { - return DiagResult(diag::err_expected_capture); + return Invalid([&] { + Diag(Tok.getLocation(), diag::err_expected_capture); + }); } + TryConsumeToken(tok::ellipsis, EllipsisLocs[2]); + if (Tok.is(tok::l_paren)) { BalancedDelimiterTracker Parens(*this, tok::l_paren); Parens.consumeOpen(); @@ -855,9 +927,9 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, ExprVector Exprs; CommaLocsTy Commas; - if (SkippedInits) { + if (Tentative) { Parens.skipToEnd(); - *SkippedInits = true; + *Tentative = LambdaIntroducerTentativeParse::Incomplete; } else if (ParseExpressionList(Exprs, Commas)) { Parens.skipToEnd(); Init = ExprError(); @@ -879,13 +951,13 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, else InitKind = LambdaCaptureInitKind::ListInit; - if (!SkippedInits) { + if (!Tentative) { Init = ParseInitializer(); } else if (Tok.is(tok::l_brace)) { BalancedDelimiterTracker Braces(*this, tok::l_brace); Braces.consumeOpen(); Braces.skipToEnd(); - *SkippedInits = true; + *Tentative = LambdaIntroducerTentativeParse::Incomplete; } else { // We're disambiguating this: // @@ -928,60 +1000,94 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, ConsumeAnnotationToken(); } } - } else - TryConsumeToken(tok::ellipsis, EllipsisLoc); - } - // If this is an init capture, process the initialization expression - // right away. For lambda init-captures such as the following: - // const int x = 10; - // auto L = [i = x+1](int a) { - // return [j = x+2, - // &k = x](char b) { }; - // }; - // keep in mind that each lambda init-capture has to have: - // - its initialization expression executed in the context - // of the enclosing/parent decl-context. - // - but the variable itself has to be 'injected' into the - // decl-context of its lambda's call-operator (which has - // not yet been created). - // Each init-expression is a full-expression that has to get - // Sema-analyzed (for capturing etc.) before its lambda's - // call-operator's decl-context, scope & scopeinfo are pushed on their - // respective stacks. Thus if any variable is odr-used in the init-capture - // it will correctly get captured in the enclosing lambda, if one exists. - // The init-variables above are created later once the lambdascope and - // call-operators decl-context is pushed onto its respective stack. - - // Since the lambda init-capture's initializer expression occurs in the - // context of the enclosing function or lambda, therefore we can not wait - // till a lambda scope has been pushed on before deciding whether the - // variable needs to be captured. We also need to process all - // lvalue-to-rvalue conversions and discarded-value conversions, - // so that we can avoid capturing certain constant variables. - // For e.g., - // void test() { - // const int x = 10; - // auto L = [&z = x](char a) { <-- don't capture by the current lambda - // return [y = x](int i) { <-- don't capture by enclosing lambda - // return y; - // } - // }; - // } - // If x was not const, the second use would require 'L' to capture, and - // that would be an error. + } + + TryConsumeToken(tok::ellipsis, EllipsisLocs[3]); + } + // Check if this is a message send before we act on a possible init-capture. + if (Tentative && Tok.is(tok::identifier) && + NextToken().isOneOf(tok::colon, tok::r_square)) { + // This can only be a message send. We're done with disambiguation. + *Tentative = LambdaIntroducerTentativeParse::MessageSend; + return false; + } + + // Ensure that any ellipsis was in the right place. + SourceLocation EllipsisLoc; + if (std::any_of(std::begin(EllipsisLocs), std::end(EllipsisLocs), + [](SourceLocation Loc) { return Loc.isValid(); })) { + // The '...' should appear before the identifier in an init-capture, and + // after the identifier otherwise. + bool InitCapture = InitKind != LambdaCaptureInitKind::NoInit; + SourceLocation *ExpectedEllipsisLoc = + !InitCapture ? &EllipsisLocs[2] : + Kind == LCK_ByRef ? &EllipsisLocs[1] : + &EllipsisLocs[0]; + EllipsisLoc = *ExpectedEllipsisLoc; + + unsigned DiagID = 0; + if (EllipsisLoc.isInvalid()) { + DiagID = diag::err_lambda_capture_misplaced_ellipsis; + for (SourceLocation Loc : EllipsisLocs) { + if (Loc.isValid()) + EllipsisLoc = Loc; + } + } else { + unsigned NumEllipses = std::accumulate( + std::begin(EllipsisLocs), std::end(EllipsisLocs), 0, + [](int N, SourceLocation Loc) { return N + Loc.isValid(); }); + if (NumEllipses > 1) + DiagID = diag::err_lambda_capture_multiple_ellipses; + } + if (DiagID) { + NonTentativeAction([&] { + // Point the diagnostic at the first misplaced ellipsis. + SourceLocation DiagLoc; + for (SourceLocation &Loc : EllipsisLocs) { + if (&Loc != ExpectedEllipsisLoc && Loc.isValid()) { + DiagLoc = Loc; + break; + } + } + assert(DiagLoc.isValid() && "no location for diagnostic"); + + // Issue the diagnostic and produce fixits showing where the ellipsis + // should have been written. + auto &&D = Diag(DiagLoc, DiagID); + if (DiagID == diag::err_lambda_capture_misplaced_ellipsis) { + SourceLocation ExpectedLoc = + InitCapture ? Loc + : Lexer::getLocForEndOfToken( + Loc, 0, PP.getSourceManager(), getLangOpts()); + D << InitCapture << FixItHint::CreateInsertion(ExpectedLoc, "..."); + } + for (SourceLocation &Loc : EllipsisLocs) { + if (&Loc != ExpectedEllipsisLoc && Loc.isValid()) + D << FixItHint::CreateRemoval(Loc); + } + }); + } + } + + // Process the init-capture initializers now rather than delaying until we + // form the lambda-expression so that they can be handled in the context + // enclosing the lambda-expression, rather than in the context of the + // lambda-expression itself. ParsedType InitCaptureType; - if (!Init.isInvalid()) + if (Init.isUsable()) Init = Actions.CorrectDelayedTyposInExpr(Init.get()); if (Init.isUsable()) { - // Get the pointer and store it in an lvalue, so we can use it as an - // out argument. - Expr *InitExpr = Init.get(); - // This performs any lvalue-to-rvalue conversions if necessary, which - // can affect what gets captured in the containing decl-context. - InitCaptureType = Actions.actOnLambdaInitCaptureInitialization( - Loc, Kind == LCK_ByRef, Id, InitKind, InitExpr); - Init = InitExpr; + NonTentativeAction([&] { + // Get the pointer and store it in an lvalue, so we can use it as an + // out argument. + Expr *InitExpr = Init.get(); + // This performs any lvalue-to-rvalue conversions if necessary, which + // can affect what gets captured in the containing decl-context. + InitCaptureType = Actions.actOnLambdaInitCaptureInitialization( + Loc, Kind == LCK_ByRef, EllipsisLoc, Id, InitKind, InitExpr); + Init = InitExpr; + }); } SourceLocation LocEnd = PrevTokLocation; @@ -992,47 +1098,14 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, T.consumeClose(); Intro.Range.setEnd(T.getCloseLocation()); - return DiagResult(); -} - -/// TryParseLambdaIntroducer - Tentatively parse a lambda introducer. -/// -/// Returns true if it hit something unexpected. -bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) { - { - bool SkippedInits = false; - TentativeParsingAction PA1(*this); - - if (ParseLambdaIntroducer(Intro, &SkippedInits)) { - PA1.Revert(); - return true; - } - - if (!SkippedInits) { - PA1.Commit(); - return false; - } - - PA1.Revert(); - } - - // Try to parse it again, but this time parse the init-captures too. - Intro = LambdaIntroducer(); - TentativeParsingAction PA2(*this); - - if (!ParseLambdaIntroducer(Intro)) { - PA2.Commit(); - return false; - } - - PA2.Revert(); - return true; + return false; } -static void -tryConsumeMutableOrConstexprToken(Parser &P, SourceLocation &MutableLoc, - SourceLocation &ConstexprLoc, - SourceLocation &DeclEndLoc) { +static void tryConsumeLambdaSpecifierToken(Parser &P, + SourceLocation &MutableLoc, + SourceLocation &ConstexprLoc, + SourceLocation &ConstevalLoc, + SourceLocation &DeclEndLoc) { assert(MutableLoc.isInvalid()); assert(ConstexprLoc.isInvalid()); // Consume constexpr-opt mutable-opt in any sequence, and set the DeclEndLoc @@ -1060,6 +1133,15 @@ tryConsumeMutableOrConstexprToken(Parser &P, SourceLocation &MutableLoc, ConstexprLoc = P.ConsumeToken(); DeclEndLoc = ConstexprLoc; break /*switch*/; + case tok::kw_consteval: + if (ConstevalLoc.isValid()) { + P.Diag(P.getCurToken().getLocation(), + diag::err_lambda_decl_specifier_repeated) + << 2 << FixItHint::CreateRemoval(P.getCurToken().getLocation()); + } + ConstevalLoc = P.ConsumeToken(); + DeclEndLoc = ConstevalLoc; + break /*switch*/; default: return; } @@ -1075,12 +1157,25 @@ addConstexprToLambdaDeclSpecifier(Parser &P, SourceLocation ConstexprLoc, : diag::warn_cxx14_compat_constexpr_on_lambda); const char *PrevSpec = nullptr; unsigned DiagID = 0; - DS.SetConstexprSpec(ConstexprLoc, PrevSpec, DiagID); + DS.SetConstexprSpec(CSK_constexpr, ConstexprLoc, PrevSpec, DiagID); assert(PrevSpec == nullptr && DiagID == 0 && "Constexpr cannot have been set previously!"); } } +static void addConstevalToLambdaDeclSpecifier(Parser &P, + SourceLocation ConstevalLoc, + DeclSpec &DS) { + if (ConstevalLoc.isValid()) { + P.Diag(ConstevalLoc, diag::warn_cxx20_compat_consteval); + const char *PrevSpec = nullptr; + unsigned DiagID = 0; + DS.SetConstexprSpec(CSK_consteval, ConstevalLoc, PrevSpec, DiagID); + if (DiagID != 0) + P.Diag(ConstevalLoc, DiagID) << PrevSpec; + } +} + /// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda /// expression. ExprResult Parser::ParseLambdaExpressionAfterIntroducer( @@ -1122,6 +1217,33 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( << A.getName()->getName(); }; + // FIXME: Consider allowing this as an extension for GCC compatibiblity. + const bool HasExplicitTemplateParams = Tok.is(tok::less); + ParseScope TemplateParamScope(this, Scope::TemplateParamScope, + /*EnteredScope=*/HasExplicitTemplateParams); + if (HasExplicitTemplateParams) { + Diag(Tok, getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_lambda_template_parameter_list + : diag::ext_lambda_template_parameter_list); + + SmallVector<NamedDecl*, 4> TemplateParams; + SourceLocation LAngleLoc, RAngleLoc; + if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(), + TemplateParams, LAngleLoc, RAngleLoc)) { + Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); + return ExprError(); + } + + if (TemplateParams.empty()) { + Diag(RAngleLoc, + diag::err_lambda_template_parameter_list_empty); + } else { + Actions.ActOnLambdaExplicitTemplateParameterList( + LAngleLoc, TemplateParams, RAngleLoc); + ++CurTemplateDepthTracker; + } + } + TypeResult TrailingReturnType; if (Tok.is(tok::l_paren)) { ParseScope PrototypeScope(this, @@ -1138,13 +1260,20 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( SourceLocation EllipsisLoc; if (Tok.isNot(tok::r_paren)) { - Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth); + Actions.RecordParsingTemplateParameterDepth( + CurTemplateDepthTracker.getOriginalDepth()); + ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc); + // For a generic lambda, each 'auto' within the parameter declaration // clause creates a template type parameter, so increment the depth. + // If we've parsed any explicit template parameters, then the depth will + // have already been incremented. So we make sure that at most a single + // depth level is added. if (Actions.getCurGenericLambda()) - ++CurTemplateDepthTracker; + CurTemplateDepthTracker.setAddedDepth(1); } + T.consumeClose(); SourceLocation RParenLoc = T.getCloseLocation(); SourceLocation DeclEndLoc = RParenLoc; @@ -1157,14 +1286,16 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( // compatible with MSVC. MaybeParseMicrosoftDeclSpecs(Attr, &DeclEndLoc); - // Parse mutable-opt and/or constexpr-opt, and update the DeclEndLoc. + // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update the + // DeclEndLoc. SourceLocation MutableLoc; SourceLocation ConstexprLoc; - tryConsumeMutableOrConstexprToken(*this, MutableLoc, ConstexprLoc, - DeclEndLoc); + SourceLocation ConstevalLoc; + tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc, + ConstevalLoc, DeclEndLoc); addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); - + addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS); // Parse exception-specification[opt]. ExceptionSpecificationType ESpecType = EST_None; SourceRange ESpecRange; @@ -1203,10 +1334,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction( - /*hasProto=*/true, - /*isAmbiguous=*/false, LParenLoc, ParamInfo.data(), + /*HasProto=*/true, + /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(), ParamInfo.size(), EllipsisLoc, RParenLoc, - /*RefQualifierIsLValueRef=*/true, + /*RefQualifierIsLvalueRef=*/true, /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType, ESpecRange, DynamicExceptions.data(), DynamicExceptionRanges.data(), DynamicExceptions.size(), @@ -1216,7 +1347,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( TrailingReturnType), std::move(Attr), DeclEndLoc); } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute, - tok::kw_constexpr) || + tok::kw_constexpr, tok::kw_consteval) || (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. @@ -1227,6 +1358,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( case tok::kw___attribute: case tok::l_square: TokKind = 2; break; case tok::kw_constexpr: TokKind = 3; break; + case tok::kw_consteval: TokKind = 4; break; default: llvm_unreachable("Unknown token kind"); } @@ -1262,14 +1394,14 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction( - /*hasProto=*/true, - /*isAmbiguous=*/false, + /*HasProto=*/true, + /*IsAmbiguous=*/false, /*LParenLoc=*/NoLoc, /*Params=*/nullptr, /*NumParams=*/0, /*EllipsisLoc=*/NoLoc, /*RParenLoc=*/NoLoc, - /*RefQualifierIsLValueRef=*/true, + /*RefQualifierIsLvalueRef=*/true, /*RefQualifierLoc=*/NoLoc, MutableLoc, EST_None, /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, @@ -1299,6 +1431,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( StmtResult Stmt(ParseCompoundStatementBody()); BodyScope.Exit(); + TemplateParamScope.Exit(); if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid()) return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope()); @@ -1568,7 +1701,7 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc, ParseUnqualifiedIdTemplateId(SS, SourceLocation(), Name, NameLoc, false, ObjectType, SecondTypeName, - /*AssumeTemplateName=*/true)) + /*AssumeTemplateId=*/true)) return ExprError(); return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind, @@ -1673,23 +1806,26 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); + PreferredType.enterTypeCast(Tok.getLocation(), TypeRep.get()); + ExprVector Exprs; CommaLocsTy CommaLocs; + auto RunSignatureHelp = [&]() { + QualType PreferredType = Actions.ProduceConstructorSignatureHelp( + getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), + DS.getEndLoc(), Exprs, T.getOpenLocation()); + CalledSignatureHelp = true; + return PreferredType; + }; + if (Tok.isNot(tok::r_paren)) { if (ParseExpressionList(Exprs, CommaLocs, [&] { - QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DS.getEndLoc(), Exprs, T.getOpenLocation()); - CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); + PreferredType.enterFunctionArgument(Tok.getLocation(), + RunSignatureHelp); })) { - if (PP.isCodeCompletionReached() && !CalledSignatureHelp) { - Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DS.getEndLoc(), Exprs, T.getOpenLocation()); - CalledSignatureHelp = true; - } + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) + RunSignatureHelp(); SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -1740,6 +1876,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, Sema::ConditionKind CK, ForRangeInfo *FRI) { ParenBraceBracketBalancer BalancerRAIIObj(*this); + PreferredType.enterCondition(Actions, Tok.getLocation()); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition); @@ -1859,6 +1996,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, diag::warn_cxx98_compat_generalized_initializer_lists); InitExpr = ParseBraceInitializer(); } else if (CopyInitialization) { + PreferredType.enterVariableInit(Tok.getLocation(), DeclOut); InitExpr = ParseAssignmentExpression(); } else if (Tok.is(tok::l_paren)) { // This was probably an attempt to initialize the variable. @@ -1995,6 +2133,13 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { case tok::kw_bool: DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID, Policy); break; +#define GENERIC_IMAGE_TYPE(ImgType, Id) \ + case tok::kw_##ImgType##_t: \ + DS.SetTypeSpecType(DeclSpec::TST_##ImgType##_t, Loc, PrevSpec, DiagID, \ + Policy); \ + break; +#include "clang/Basic/OpenCLImageTypes.def" + case tok::annot_decltype: case tok::kw_decltype: DS.SetRangeEnd(ParseDecltypeSpecifier(DS)); @@ -2090,9 +2235,15 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, TemplateKWLoc.isValid(), Id, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization); + // If lookup found nothing but we're assuming that this is a template + // name, double-check that makes sense syntactically before committing + // to it. + if (TNK == TNK_Undeclared_template && + isTemplateArgumentList(0) == TPResult::False) + return false; if (TNK == TNK_Non_template && MemberOfUnknownSpecialization && - ObjectType && IsTemplateArgumentList()) { + ObjectType && isTemplateArgumentList(0) == TPResult::True) { // We have something like t->getAs<T>(), where getAs is a // member of an unknown specialization. However, this will only // parse correctly as a template, so suggest the keyword 'template' @@ -2196,11 +2347,9 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs); // Constructor and destructor names. - TypeResult Type - = Actions.ActOnTemplateIdType(SS, TemplateKWLoc, - Template, Name, NameLoc, - LAngleLoc, TemplateArgsPtr, RAngleLoc, - /*IsCtorOrDtorName=*/true); + TypeResult Type = Actions.ActOnTemplateIdType( + getCurScope(), SS, TemplateKWLoc, Template, Name, NameLoc, LAngleLoc, + TemplateArgsPtr, RAngleLoc, /*IsCtorOrDtorName=*/true); if (Type.isInvalid()) return true; @@ -2836,23 +2985,21 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { ConstructorLParen = T.getOpenLocation(); if (Tok.isNot(tok::r_paren)) { CommaLocsTy CommaLocs; + auto RunSignatureHelp = [&]() { + ParsedType TypeRep = + Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); + QualType PreferredType = Actions.ProduceConstructorSignatureHelp( + getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), + DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); + CalledSignatureHelp = true; + return PreferredType; + }; if (ParseExpressionList(ConstructorArgs, CommaLocs, [&] { - ParsedType TypeRep = - Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); - QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); - CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); + PreferredType.enterFunctionArgument(Tok.getLocation(), + RunSignatureHelp); })) { - if (PP.isCodeCompletionReached() && !CalledSignatureHelp) { - ParsedType TypeRep = - Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); - Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); - CalledSignatureHelp = true; - } + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) + RunSignatureHelp(); SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } @@ -2883,12 +3030,12 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { /// passed to ParseDeclaratorInternal. /// /// direct-new-declarator: -/// '[' expression ']' +/// '[' expression[opt] ']' /// direct-new-declarator '[' constant-expression ']' /// void Parser::ParseDirectNewDeclarator(Declarator &D) { // Parse the array dimensions. - bool first = true; + bool First = true; while (Tok.is(tok::l_square)) { // An array-size expression can't start with a lambda. if (CheckProhibitedCXX11Attribute()) @@ -2897,14 +3044,15 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); - ExprResult Size(first ? ParseExpression() - : ParseConstantExpression()); + ExprResult Size = + First ? (Tok.is(tok::r_square) ? ExprResult() : ParseExpression()) + : ParseConstantExpression(); if (Size.isInvalid()) { // Recover SkipUntil(tok::r_square, StopAtSemi); return; } - first = false; + First = false; T.consumeClose(); @@ -2913,7 +3061,7 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { MaybeParseCXX11Attributes(Attrs); D.AddTypeInfo(DeclaratorChunk::getArray(0, - /*static=*/false, /*star=*/false, + /*isStatic=*/false, /*isStar=*/false, Size.get(), T.getOpenLocation(), T.getCloseLocation()), std::move(Attrs), T.getCloseLocation()); @@ -2975,8 +3123,59 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { // [Footnote: A lambda expression with a lambda-introducer that consists // of empty square brackets can follow the delete keyword if // the lambda expression is enclosed in parentheses.] - // FIXME: Produce a better diagnostic if the '[]' is unambiguously a - // lambda-introducer. + + const Token Next = GetLookAheadToken(2); + + // Basic lookahead to check if we have a lambda expression. + if (Next.isOneOf(tok::l_brace, tok::less) || + (Next.is(tok::l_paren) && + (GetLookAheadToken(3).is(tok::r_paren) || + (GetLookAheadToken(3).is(tok::identifier) && + GetLookAheadToken(4).is(tok::identifier))))) { + TentativeParsingAction TPA(*this); + SourceLocation LSquareLoc = Tok.getLocation(); + SourceLocation RSquareLoc = NextToken().getLocation(); + + // SkipUntil can't skip pairs of </*...*/>; don't emit a FixIt in this + // case. + SkipUntil({tok::l_brace, tok::less}, StopBeforeMatch); + SourceLocation RBraceLoc; + bool EmitFixIt = false; + if (Tok.is(tok::l_brace)) { + ConsumeBrace(); + SkipUntil(tok::r_brace, StopBeforeMatch); + RBraceLoc = Tok.getLocation(); + EmitFixIt = true; + } + + TPA.Revert(); + + if (EmitFixIt) + Diag(Start, diag::err_lambda_after_delete) + << SourceRange(Start, RSquareLoc) + << FixItHint::CreateInsertion(LSquareLoc, "(") + << FixItHint::CreateInsertion( + Lexer::getLocForEndOfToken( + RBraceLoc, 0, Actions.getSourceManager(), getLangOpts()), + ")"); + else + Diag(Start, diag::err_lambda_after_delete) + << SourceRange(Start, RSquareLoc); + + // Warn that the non-capturing lambda isn't surrounded by parentheses + // to disambiguate it from 'delete[]'. + ExprResult Lambda = ParseLambdaExpression(); + if (Lambda.isInvalid()) + return ExprError(); + + // Evaluate any postfix expressions used on the lambda. + Lambda = ParsePostfixExpressionSuffix(Lambda); + if (Lambda.isInvalid()) + return ExprError(); + return Actions.ActOnCXXDelete(Start, UseGlobal, /*ArrayForm=*/false, + Lambda.get()); + } + ArrayDelete = true; BalancedDelimiterTracker T(*this, tok::l_square); @@ -3241,7 +3440,8 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, Toks.push_back(Tok); // Re-enter the stored parenthesized tokens into the token stream, so we may // parse them now. - PP.EnterTokenStream(Toks, true /*DisableMacroExpansion*/); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion*/ true, + /*IsReinject*/ true); // Drop the current token and bring the first cached one. It's the same token // as when we entered this function. ConsumeAnyToken(); @@ -3313,3 +3513,37 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, ConsumeAnyToken(); return Result; } + +/// Parse a __builtin_bit_cast(T, E). +ExprResult Parser::ParseBuiltinBitCast() { + SourceLocation KWLoc = ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, "__builtin_bit_cast")) + return ExprError(); + + // Parse the common declaration-specifiers piece. + DeclSpec DS(AttrFactory); + ParseSpecifierQualifierList(DS); + + // Parse the abstract-declarator, if present. + Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext); + ParseDeclarator(DeclaratorInfo); + + if (ExpectAndConsume(tok::comma)) { + Diag(Tok.getLocation(), diag::err_expected) << tok::comma; + SkipUntil(tok::r_paren, StopAtSemi); + return ExprError(); + } + + ExprResult Operand = ParseExpression(); + + if (T.consumeClose()) + return ExprError(); + + if (Operand.isInvalid() || DeclaratorInfo.isInvalidType()) + return ExprError(); + + return Actions.ActOnBuiltinBitCastExpr(KWLoc, DeclaratorInfo, Operand, + T.getCloseLocation()); +} diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 7742a5087cf01..7a455484b902f 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -1,9 +1,8 @@ //===--- ParseInit.cpp - Initializer Parsing ------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -66,15 +65,28 @@ bool Parser::MayBeDesignationStart() { // Parse up to (at most) the token after the closing ']' to determine // whether this is a C99 designator or a lambda. - TentativeParsingAction Tentative(*this); + RevertingTentativeParsingAction Tentative(*this); LambdaIntroducer Intro; - bool SkippedInits = false; - Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro, &SkippedInits)); + LambdaIntroducerTentativeParse ParseResult; + if (ParseLambdaIntroducer(Intro, &ParseResult)) { + // Hit and diagnosed an error in a lambda. + // FIXME: Tell the caller this happened so they can recover. + return true; + } + + switch (ParseResult) { + case LambdaIntroducerTentativeParse::Success: + case LambdaIntroducerTentativeParse::Incomplete: + // Might be a lambda-expression. Keep looking. + // FIXME: If our tentative parse was not incomplete, parse the lambda from + // here rather than throwing away then reparsing the LambdaIntroducer. + break; - if (DiagID) { - // If this can't be a lambda capture list, it's a designator. - Tentative.Revert(); + case LambdaIntroducerTentativeParse::MessageSend: + case LambdaIntroducerTentativeParse::Invalid: + // Can't be a lambda-expression. Treat it as a designator. + // FIXME: Should we disambiguate against a message-send? return true; } @@ -83,11 +95,7 @@ bool Parser::MayBeDesignationStart() { // lambda expression. This decision favors lambdas over the older // GNU designator syntax, which allows one to omit the '=', but is // consistent with GCC. - tok::TokenKind Kind = Tok.getKind(); - // FIXME: If we didn't skip any inits, parse the lambda from here - // rather than throwing away then reparsing the LambdaIntroducer. - Tentative.Revert(); - return Kind == tok::equal; + return Tok.is(tok::equal); } static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc, diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index bd55f71793995..8937a0986c956 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -1,9 +1,8 @@ //===--- ParseObjC.cpp - Objective C Parsing ------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -65,7 +64,7 @@ Parser::ParseObjCAtDirectives(ParsedAttributesWithRange &Attrs) { case tok::objc_protocol: return ParseObjCAtProtocolDeclaration(AtLoc, Attrs); case tok::objc_implementation: - return ParseObjCAtImplementationDeclaration(AtLoc); + return ParseObjCAtImplementationDeclaration(AtLoc, Attrs); case tok::objc_end: return ParseObjCAtEndDeclaration(AtLoc); case tok::objc_compatibility_alias: @@ -624,6 +623,8 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, } // Ignore excess semicolons. if (Tok.is(tok::semi)) { + // FIXME: This should use ConsumeExtraSemi() for extraneous semicolons, + // to make -Wextra-semi diagnose them. ConsumeToken(); continue; } @@ -647,7 +648,19 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, // erroneous r_brace would cause an infinite loop if not handled here. if (Tok.is(tok::r_brace)) break; + ParsedAttributesWithRange attrs(AttrFactory); + + // Since we call ParseDeclarationOrFunctionDefinition() instead of + // ParseExternalDeclaration() below (so that this doesn't parse nested + // @interfaces), this needs to duplicate some code from the latter. + if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) { + SourceLocation DeclEnd; + allTUVariables.push_back( + ParseDeclaration(DeclaratorContext::FileContext, DeclEnd, attrs)); + continue; + } + allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs)); continue; } @@ -1234,11 +1247,11 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - SourceLocation TypeStartLoc = Tok.getLocation(); ObjCDeclContextSwitch ObjCDC(*this); // Parse type qualifiers, in, inout, etc. ParseObjCTypeQualifierList(DS, context); + SourceLocation TypeStartLoc = Tok.getLocation(); ParsedType Ty; if (isTypeSpecifierQualifier() || isObjCInstancetype()) { @@ -1876,6 +1889,7 @@ void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocatio /// ';' /// objc-instance-variable-decl-list objc-visibility-spec /// objc-instance-variable-decl-list objc-instance-variable-decl ';' +/// objc-instance-variable-decl-list static_assert-declaration /// objc-instance-variable-decl-list ';' /// /// objc-visibility-spec: @@ -1929,7 +1943,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, Tok.setLocation(Tok.getLocation().getLocWithOffset(-1)); Tok.setKind(tok::at); Tok.setLength(1); - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject*/true); HelperActionsForIvarDeclarations(interfaceDecl, atLoc, T, AllIvarDecls, true); return; @@ -1946,6 +1960,15 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, return cutOffParsing(); } + // This needs to duplicate a small amount of code from + // ParseStructUnionBody() for things that should work in both + // C struct and in Objective-C class instance variables. + if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) { + SourceLocation DeclEnd; + ParseStaticAssertDeclaration(DeclEnd); + continue; + } + auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) { Actions.ActOnObjCContainerStartDefinition(interfaceDecl); // Install the declarator into the interface decl. @@ -2074,7 +2097,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, /// objc-category-implementation-prologue: /// @implementation identifier ( identifier ) Parser::DeclGroupPtrTy -Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { +Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc, + ParsedAttributes &Attrs) { assert(Tok.isObjCAtKeyword(tok::objc_implementation) && "ParseObjCAtImplementationDeclaration(): Expected @implementation"); CheckNestedObjCContexts(AtLoc); @@ -2151,8 +2175,7 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { /*consumeLastToken=*/true); } ObjCImpDecl = Actions.ActOnStartCategoryImplementation( - AtLoc, nameId, nameLoc, categoryId, - categoryLoc); + AtLoc, nameId, nameLoc, categoryId, categoryLoc, Attrs); } else { // We have a class implementation @@ -2166,8 +2189,7 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { superClassLoc = ConsumeToken(); // Consume super class name } ObjCImpDecl = Actions.ActOnStartClassImplementation( - AtLoc, nameId, nameLoc, - superClassId, superClassLoc); + AtLoc, nameId, nameLoc, superClassId, superClassLoc, Attrs); if (Tok.is(tok::l_brace)) // we have ivars ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc); @@ -2704,7 +2726,8 @@ Decl *Parser::ParseObjCMethodDefinition() { return MDecl; } -StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { +StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc, + ParsedStmtContext StmtCtx) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCAtStatement(getCurScope()); cutOffParsing(); @@ -2741,7 +2764,7 @@ StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { // Otherwise, eat the semicolon. ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); - return Actions.ActOnExprStmt(Res, isExprValueDiscarded()); + return handleExprStmt(Res, StmtCtx); } ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { @@ -3171,15 +3194,15 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, if (SuperLoc.isValid()) Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, KeyIdents, - /*AtArgumentEpression=*/true); + /*AtArgumentExpression=*/true); else if (ReceiverType) Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, KeyIdents, - /*AtArgumentEpression=*/true); + /*AtArgumentExpression=*/true); else Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, KeyIdents, - /*AtArgumentEpression=*/true); + /*AtArgumentExpression=*/true); cutOffParsing(); return ExprError(); @@ -3209,15 +3232,15 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, if (SuperLoc.isValid()) Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, KeyIdents, - /*AtArgumentEpression=*/false); + /*AtArgumentExpression=*/false); else if (ReceiverType) Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, KeyIdents, - /*AtArgumentEpression=*/false); + /*AtArgumentExpression=*/false); else Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, KeyIdents, - /*AtArgumentEpression=*/false); + /*AtArgumentExpression=*/false); cutOffParsing(); return ExprError(); } @@ -3631,7 +3654,7 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { // Append the current token at the end of the new token stream so that it // doesn't get lost. LM.Toks.push_back(Tok); - PP.EnterTokenStream(LM.Toks, true); + PP.EnterTokenStream(LM.Toks, true, /*IsReinject*/true); // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index dd2a8aae9f2fb..52a68f6d6935c 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -1,9 +1,8 @@ //===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// \file @@ -41,18 +40,21 @@ enum OpenMPDirectiveKindEx { OMPD_update, OMPD_distribute_parallel, OMPD_teams_distribute_parallel, - OMPD_target_teams_distribute_parallel + OMPD_target_teams_distribute_parallel, + OMPD_mapper, }; -class ThreadprivateListParserHelper final { +class DeclDirectiveListParserHelper final { SmallVector<Expr *, 4> Identifiers; Parser *P; + OpenMPDirectiveKind Kind; public: - ThreadprivateListParserHelper(Parser *P) : P(P) {} + DeclDirectiveListParserHelper(Parser *P, OpenMPDirectiveKind Kind) + : P(P), Kind(Kind) {} void operator()(CXXScopeSpec &SS, DeclarationNameInfo NameInfo) { - ExprResult Res = - P->getActions().ActOnOpenMPIdExpression(P->getCurScope(), SS, NameInfo); + ExprResult Res = P->getActions().ActOnOpenMPIdExpression( + P->getCurScope(), SS, NameInfo, Kind); if (Res.isUsable()) Identifiers.push_back(Res.get()); } @@ -77,6 +79,7 @@ static unsigned getOpenMPDirectiveKindEx(StringRef S) { .Case("point", OMPD_point) .Case("reduction", OMPD_reduction) .Case("update", OMPD_update) + .Case("mapper", OMPD_mapper) .Default(OMPD_unknown); } @@ -87,6 +90,7 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) { static const unsigned F[][3] = { {OMPD_cancellation, OMPD_point, OMPD_cancellation_point}, {OMPD_declare, OMPD_reduction, OMPD_declare_reduction}, + {OMPD_declare, OMPD_mapper, OMPD_declare_mapper}, {OMPD_declare, OMPD_simd, OMPD_declare_simd}, {OMPD_declare, OMPD_target, OMPD_declare_target}, {OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel}, @@ -422,21 +426,19 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) { CommaLocsTy CommaLocs; SourceLocation LParLoc = T.getOpenLocation(); - if (ParseExpressionList( - Exprs, CommaLocs, [this, OmpPrivParm, LParLoc, &Exprs] { - QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), - OmpPrivParm->getType()->getCanonicalTypeInternal(), - OmpPrivParm->getLocation(), Exprs, LParLoc); - CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); - })) { - if (PP.isCodeCompletionReached() && !CalledSignatureHelp) { - Actions.ProduceConstructorSignatureHelp( - getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(), - OmpPrivParm->getLocation(), Exprs, LParLoc); - CalledSignatureHelp = true; - } + auto RunSignatureHelp = [this, OmpPrivParm, LParLoc, &Exprs]() { + QualType PreferredType = Actions.ProduceConstructorSignatureHelp( + getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(), + OmpPrivParm->getLocation(), Exprs, LParLoc); + CalledSignatureHelp = true; + return PreferredType; + }; + if (ParseExpressionList(Exprs, CommaLocs, [&] { + PreferredType.enterFunctionArgument(Tok.getLocation(), + RunSignatureHelp); + })) { + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) + RunSignatureHelp(); Actions.ActOnInitializerError(OmpPrivParm); SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } else { @@ -470,6 +472,141 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) { } } +/// Parses 'omp declare mapper' directive. +/// +/// declare-mapper-directive: +/// annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifier> ':'] +/// <type> <var> ')' [<clause>[[,] <clause>] ... ] +/// annot_pragma_openmp_end +/// <mapper-identifier> and <var> are base language identifiers. +/// +Parser::DeclGroupPtrTy +Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) { + bool IsCorrect = true; + // Parse '(' + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPDirectiveName(OMPD_declare_mapper))) { + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + return DeclGroupPtrTy(); + } + + // Parse <mapper-identifier> + auto &DeclNames = Actions.getASTContext().DeclarationNames; + DeclarationName MapperId; + if (PP.LookAhead(0).is(tok::colon)) { + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_default)) { + Diag(Tok.getLocation(), diag::err_omp_mapper_illegal_identifier); + IsCorrect = false; + } else { + MapperId = DeclNames.getIdentifier(Tok.getIdentifierInfo()); + } + ConsumeToken(); + // Consume ':'. + ExpectAndConsume(tok::colon); + } else { + // If no mapper identifier is provided, its name is "default" by default + MapperId = + DeclNames.getIdentifier(&Actions.getASTContext().Idents.get("default")); + } + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return DeclGroupPtrTy(); + + // Parse <type> <var> + DeclarationName VName; + QualType MapperType; + SourceRange Range; + TypeResult ParsedType = parseOpenMPDeclareMapperVarDecl(Range, VName, AS); + if (ParsedType.isUsable()) + MapperType = + Actions.ActOnOpenMPDeclareMapperType(Range.getBegin(), ParsedType); + if (MapperType.isNull()) + IsCorrect = false; + if (!IsCorrect) { + SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch); + return DeclGroupPtrTy(); + } + + // Consume ')'. + IsCorrect &= !T.consumeClose(); + if (!IsCorrect) { + SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch); + return DeclGroupPtrTy(); + } + + // Enter scope. + OMPDeclareMapperDecl *DMD = Actions.ActOnOpenMPDeclareMapperDirectiveStart( + getCurScope(), Actions.getCurLexicalContext(), MapperId, MapperType, + Range.getBegin(), VName, AS); + DeclarationNameInfo DirName; + SourceLocation Loc = Tok.getLocation(); + unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; + ParseScope OMPDirectiveScope(this, ScopeFlags); + Actions.StartOpenMPDSABlock(OMPD_declare_mapper, DirName, getCurScope(), Loc); + + // Add the mapper variable declaration. + Actions.ActOnOpenMPDeclareMapperDirectiveVarDecl( + DMD, getCurScope(), MapperType, Range.getBegin(), VName); + + // Parse map clauses. + SmallVector<OMPClause *, 6> Clauses; + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OpenMPClauseKind CKind = Tok.isAnnotation() + ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + Actions.StartOpenMPClause(CKind); + OMPClause *Clause = + ParseOpenMPClause(OMPD_declare_mapper, CKind, Clauses.size() == 0); + if (Clause) + Clauses.push_back(Clause); + else + IsCorrect = false; + // Skip ',' if any. + if (Tok.is(tok::comma)) + ConsumeToken(); + Actions.EndOpenMPClause(); + } + if (Clauses.empty()) { + Diag(Tok, diag::err_omp_expected_clause) + << getOpenMPDirectiveName(OMPD_declare_mapper); + IsCorrect = false; + } + + // Exit scope. + Actions.EndOpenMPDSABlock(nullptr); + OMPDirectiveScope.Exit(); + + DeclGroupPtrTy DGP = + Actions.ActOnOpenMPDeclareMapperDirectiveEnd(DMD, getCurScope(), Clauses); + if (!IsCorrect) + return DeclGroupPtrTy(); + return DGP; +} + +TypeResult Parser::parseOpenMPDeclareMapperVarDecl(SourceRange &Range, + DeclarationName &Name, + AccessSpecifier AS) { + // Parse the common declaration-specifiers piece. + Parser::DeclSpecContext DSC = Parser::DeclSpecContext::DSC_type_specifier; + DeclSpec DS(AttrFactory); + ParseSpecifierQualifierList(DS, AS, DSC); + + // Parse the declarator. + DeclaratorContext Context = DeclaratorContext::PrototypeContext; + Declarator DeclaratorInfo(DS, Context); + ParseDeclarator(DeclaratorInfo); + Range = DeclaratorInfo.getSourceRange(); + if (DeclaratorInfo.getIdentifier() == nullptr) { + Diag(Tok.getLocation(), diag::err_omp_mapper_expected_declarator); + return true; + } + Name = Actions.GetNameForDeclarator(DeclaratorInfo).getName(); + + return Actions.ActOnOpenMPDeclareMapperVarDecl(getCurScope(), DeclaratorInfo); +} + namespace { /// RAII that recreates function context for correct parsing of clauses of /// 'declare simd' construct. @@ -610,8 +747,9 @@ static bool parseDeclareSimdClauses( Parser::DeclGroupPtrTy Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr, CachedTokens &Toks, SourceLocation Loc) { - PP.EnterToken(Tok); - PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); + PP.EnterToken(Tok, /*IsReinject*/ true); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject*/ true); // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); @@ -704,10 +842,19 @@ void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind, /// annot_pragma_openmp 'threadprivate' simple-variable-list /// annot_pragma_openmp_end /// +/// allocate-directive: +/// annot_pragma_openmp 'allocate' simple-variable-list [<clause>] +/// annot_pragma_openmp_end +/// /// declare-reduction-directive: /// annot_pragma_openmp 'declare' 'reduction' [...] /// annot_pragma_openmp_end /// +/// declare-mapper-directive: +/// annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifer> ':'] +/// <type> <var> ')' [<clause>[[,] <clause>] ... ] +/// annot_pragma_openmp_end +/// /// declare-simd-directive: /// annot_pragma_openmp 'declare simd' {<clause> [,]} /// annot_pragma_openmp_end @@ -729,13 +876,14 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( switch (DKind) { case OMPD_threadprivate: { ConsumeToken(); - ThreadprivateListParserHelper Helper(this); - if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Helper, true)) { + DeclDirectiveListParserHelper Helper(this, DKind); + if (!ParseOpenMPSimpleVarList(DKind, Helper, + /*AllowScopeSpecifier=*/true)) { // The last seen token is annot_pragma_openmp_end - need to check for // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(OMPD_threadprivate); + << getOpenMPDirectiveName(DKind); SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); } // Skip the last annot_pragma_openmp_end. @@ -745,13 +893,59 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( } break; } + case OMPD_allocate: { + ConsumeToken(); + DeclDirectiveListParserHelper Helper(this, DKind); + if (!ParseOpenMPSimpleVarList(DKind, Helper, + /*AllowScopeSpecifier=*/true)) { + SmallVector<OMPClause *, 1> Clauses; + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, + OMPC_unknown + 1> + FirstClauses(OMPC_unknown + 1); + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OpenMPClauseKind CKind = + Tok.isAnnotation() ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + Actions.StartOpenMPClause(CKind); + OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind, + !FirstClauses[CKind].getInt()); + SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, + StopBeforeMatch); + FirstClauses[CKind].setInt(true); + if (Clause != nullptr) + Clauses.push_back(Clause); + if (Tok.is(tok::annot_pragma_openmp_end)) { + Actions.EndOpenMPClause(); + break; + } + // Skip ',' if any. + if (Tok.is(tok::comma)) + ConsumeToken(); + Actions.EndOpenMPClause(); + } + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(DKind); + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + } + } + // Skip the last annot_pragma_openmp_end. + ConsumeAnnotationToken(); + return Actions.ActOnOpenMPAllocateDirective(Loc, Helper.getIdentifiers(), + Clauses); + } + break; + } case OMPD_requires: { SourceLocation StartLoc = ConsumeToken(); SmallVector<OMPClause *, 5> Clauses; SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1> FirstClauses(OMPC_unknown + 1); if (Tok.is(tok::annot_pragma_openmp_end)) { - Diag(Tok, diag::err_omp_expected_clause) + Diag(Tok, diag::err_omp_expected_clause) << getOpenMPDirectiveName(OMPD_requires); break; } @@ -760,9 +954,10 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( ? OMPC_unknown : getOpenMPClauseKind(PP.getSpelling(Tok)); Actions.StartOpenMPClause(CKind); - OMPClause *Clause = - ParseOpenMPClause(OMPD_requires, CKind, !FirstClauses[CKind].getInt()); - SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, StopBeforeMatch); + OMPClause *Clause = ParseOpenMPClause(OMPD_requires, CKind, + !FirstClauses[CKind].getInt()); + SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, + StopBeforeMatch); FirstClauses[CKind].setInt(true); if (Clause != nullptr) Clauses.push_back(Clause); @@ -801,6 +996,15 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( return Res; } break; + case OMPD_declare_mapper: { + ConsumeToken(); + if (DeclGroupPtrTy Res = ParseOpenMPDeclareMapperDirective(AS)) { + // Skip the last annot_pragma_openmp_end. + ConsumeAnnotationToken(); + return Res; + } + break; + } case OMPD_declare_simd: { // The syntax is: // { #pragma omp declare simd } @@ -949,12 +1153,21 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( /// annot_pragma_openmp 'threadprivate' simple-variable-list /// annot_pragma_openmp_end /// +/// allocate-directive: +/// annot_pragma_openmp 'allocate' simple-variable-list +/// annot_pragma_openmp_end +/// /// declare-reduction-directive: /// annot_pragma_openmp 'declare' 'reduction' '(' <reduction_id> ':' /// <type> {',' <type>} ':' <expression> ')' ['initializer' '(' /// ('omp_priv' '=' <expression>|<function_call>) ')'] /// annot_pragma_openmp_end /// +/// declare-mapper-directive: +/// annot_pragma_openmp 'declare' 'mapper' '(' [<mapper-identifer> ':'] +/// <type> <var> ')' [<clause>[[,] <clause>] ... ] +/// annot_pragma_openmp_end +/// /// executable-directive: /// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' | /// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] | @@ -976,8 +1189,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( /// 'target teams distribute simd' {clause} /// annot_pragma_openmp_end /// -StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( - AllowedConstructsKind Allowed) { +StmtResult +Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); ParenBraceBracketBalancer BalancerRAIIObj(*this); SmallVector<OMPClause *, 5> Clauses; @@ -996,18 +1209,21 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( switch (DKind) { case OMPD_threadprivate: { - if (Allowed != ACK_Any) { + // FIXME: Should this be permitted in C++? + if ((StmtCtx & ParsedStmtContext::AllowDeclarationsInC) == + ParsedStmtContext()) { Diag(Tok, diag::err_omp_immediate_directive) << getOpenMPDirectiveName(DKind) << 0; } ConsumeToken(); - ThreadprivateListParserHelper Helper(this); - if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Helper, false)) { + DeclDirectiveListParserHelper Helper(this, DKind); + if (!ParseOpenMPSimpleVarList(DKind, Helper, + /*AllowScopeSpecifier=*/false)) { // The last seen token is annot_pragma_openmp_end - need to check for // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(OMPD_threadprivate); + << getOpenMPDirectiveName(DKind); SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); } DeclGroupPtrTy Res = Actions.ActOnOpenMPThreadprivateDirective( @@ -1017,6 +1233,58 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( SkipUntil(tok::annot_pragma_openmp_end); break; } + case OMPD_allocate: { + // FIXME: Should this be permitted in C++? + if ((StmtCtx & ParsedStmtContext::AllowDeclarationsInC) == + ParsedStmtContext()) { + Diag(Tok, diag::err_omp_immediate_directive) + << getOpenMPDirectiveName(DKind) << 0; + } + ConsumeToken(); + DeclDirectiveListParserHelper Helper(this, DKind); + if (!ParseOpenMPSimpleVarList(DKind, Helper, + /*AllowScopeSpecifier=*/false)) { + SmallVector<OMPClause *, 1> Clauses; + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, + OMPC_unknown + 1> + FirstClauses(OMPC_unknown + 1); + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OpenMPClauseKind CKind = + Tok.isAnnotation() ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + Actions.StartOpenMPClause(CKind); + OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind, + !FirstClauses[CKind].getInt()); + SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end, + StopBeforeMatch); + FirstClauses[CKind].setInt(true); + if (Clause != nullptr) + Clauses.push_back(Clause); + if (Tok.is(tok::annot_pragma_openmp_end)) { + Actions.EndOpenMPClause(); + break; + } + // Skip ',' if any. + if (Tok.is(tok::comma)) + ConsumeToken(); + Actions.EndOpenMPClause(); + } + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(DKind); + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + } + } + DeclGroupPtrTy Res = Actions.ActOnOpenMPAllocateDirective( + Loc, Helper.getIdentifiers(), Clauses); + Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); + } + SkipUntil(tok::annot_pragma_openmp_end); + break; + } case OMPD_declare_reduction: ConsumeToken(); if (DeclGroupPtrTy Res = @@ -1035,12 +1303,24 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( SkipUntil(tok::annot_pragma_openmp_end); } break; + case OMPD_declare_mapper: { + ConsumeToken(); + if (DeclGroupPtrTy Res = + ParseOpenMPDeclareMapperDirective(/*AS=*/AS_none)) { + // Skip the last annot_pragma_openmp_end. + ConsumeAnnotationToken(); + Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); + } else { + SkipUntil(tok::annot_pragma_openmp_end); + } + break; + } case OMPD_flush: if (PP.LookAhead(0).is(tok::l_paren)) { FlushHasClause = true; // Push copy of the current token back to stream to properly parse // pseudo-clause OMPFlushClause. - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject*/ true); } LLVM_FALLTHROUGH; case OMPD_taskyield: @@ -1051,7 +1331,8 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( case OMPD_target_enter_data: case OMPD_target_exit_data: case OMPD_target_update: - if (Allowed == ACK_StatementsOpenMPNonStandalone) { + if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == + ParsedStmtContext()) { Diag(Tok, diag::err_omp_immediate_directive) << getOpenMPDirectiveName(DKind) << 0; } @@ -1154,7 +1435,8 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( // If the depend clause is specified, the ordered construct is a stand-alone // directive. if (DKind == OMPD_ordered && FirstClauses[OMPC_depend].getInt()) { - if (Allowed == ACK_StatementsOpenMPNonStandalone) { + if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == + ParsedStmtContext()) { Diag(Loc, diag::err_omp_immediate_directive) << getOpenMPDirectiveName(DKind) << 1 << getOpenMPClauseName(OMPC_depend); @@ -1281,7 +1563,7 @@ bool Parser::ParseOpenMPSimpleVarList( /// thread_limit-clause | priority-clause | grainsize-clause | /// nogroup-clause | num_tasks-clause | hint-clause | to-clause | /// from-clause | is_device_ptr-clause | task_reduction-clause | -/// in_reduction-clause +/// in_reduction-clause | allocator-clause | allocate-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { @@ -1310,6 +1592,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_grainsize: case OMPC_num_tasks: case OMPC_hint: + case OMPC_allocator: // OpenMP [2.5, Restrictions] // At most one num_threads clause can appear on the directive. // OpenMP [2.8.1, simd construct, Restrictions] @@ -1330,6 +1613,8 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, // At most one grainsize clause can appear on the directive. // OpenMP [2.9.2, taskloop Construct, Restrictions] // At most one num_tasks clause can appear on the directive. + // OpenMP [2.11.3, allocate Directive, Restrictions] + // At most one allocator clause can appear on the directive. if (!FirstClause) { Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0; @@ -1424,6 +1709,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_from: case OMPC_use_device_ptr: case OMPC_is_device_ptr: + case OMPC_allocate: Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective); break; case OMPC_unknown: @@ -1496,6 +1782,9 @@ ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName, /// hint-clause: /// 'hint' '(' expression ')' /// +/// allocator-clause: +/// 'allocator' '(' expression ')' +/// OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind, bool ParseOnly) { SourceLocation Loc = ConsumeToken(); @@ -1787,38 +2076,70 @@ static OpenMPMapModifierKind isMapModifier(Parser &P) { return TypeModifier; } +/// Parse the mapper modifier in map, to, and from clauses. +bool Parser::parseMapperModifier(OpenMPVarListDataTy &Data) { + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::colon); + if (T.expectAndConsume(diag::err_expected_lparen_after, "mapper")) { + SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + return true; + } + // Parse mapper-identifier + if (getLangOpts().CPlusPlus) + ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec, + /*ObjectType=*/nullptr, + /*EnteringContext=*/false); + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_default)) { + Diag(Tok.getLocation(), diag::err_omp_mapper_illegal_identifier); + SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + return true; + } + auto &DeclNames = Actions.getASTContext().DeclarationNames; + Data.ReductionOrMapperId = DeclarationNameInfo( + DeclNames.getIdentifier(Tok.getIdentifierInfo()), Tok.getLocation()); + ConsumeToken(); + // Parse ')'. + return T.consumeClose(); +} + /// Parse map-type-modifiers in map clause. /// map([ [map-type-modifier[,] [map-type-modifier[,] ...] map-type : ] list) -/// where, map-type-modifier ::= always | close -static void parseMapTypeModifiers(Parser &P, - Parser::OpenMPVarListDataTy &Data) { - Preprocessor &PP = P.getPreprocessor(); - while (P.getCurToken().isNot(tok::colon)) { - Token Tok = P.getCurToken(); - OpenMPMapModifierKind TypeModifier = isMapModifier(P); +/// where, map-type-modifier ::= always | close | mapper(mapper-identifier) +bool Parser::parseMapTypeModifiers(OpenMPVarListDataTy &Data) { + while (getCurToken().isNot(tok::colon)) { + OpenMPMapModifierKind TypeModifier = isMapModifier(*this); if (TypeModifier == OMPC_MAP_MODIFIER_always || TypeModifier == OMPC_MAP_MODIFIER_close) { Data.MapTypeModifiers.push_back(TypeModifier); Data.MapTypeModifiersLoc.push_back(Tok.getLocation()); - P.ConsumeToken(); + ConsumeToken(); + } else if (TypeModifier == OMPC_MAP_MODIFIER_mapper) { + Data.MapTypeModifiers.push_back(TypeModifier); + Data.MapTypeModifiersLoc.push_back(Tok.getLocation()); + ConsumeToken(); + if (parseMapperModifier(Data)) + return true; } else { // For the case of unknown map-type-modifier or a map-type. // Map-type is followed by a colon; the function returns when it // encounters a token followed by a colon. if (Tok.is(tok::comma)) { - P.Diag(Tok, diag::err_omp_map_type_modifier_missing); - P.ConsumeToken(); + Diag(Tok, diag::err_omp_map_type_modifier_missing); + ConsumeToken(); continue; } // Potential map-type token as it is followed by a colon. if (PP.LookAhead(0).is(tok::colon)) - return; - P.Diag(Tok, diag::err_omp_unknown_map_type_modifier); - P.ConsumeToken(); + return false; + Diag(Tok, diag::err_omp_unknown_map_type_modifier); + ConsumeToken(); } - if (P.getCurToken().is(tok::comma)) - P.ConsumeToken(); + if (getCurToken().is(tok::comma)) + ConsumeToken(); } + return false; } /// Checks if the token is a valid map-type. @@ -1835,7 +2156,7 @@ static OpenMPMapClauseKind isMapType(Parser &P) { /// Parse map-type in map clause. /// map([ [map-type-modifier[,] [map-type-modifier[,] ...] map-type : ] list) -/// where, map-type ::= to | from | tofrom | alloc | release | delete +/// where, map-type ::= to | from | tofrom | alloc | release | delete static void parseMapType(Parser &P, Parser::OpenMPVarListDataTy &Data) { Token Tok = P.getCurToken(); if (Tok.is(tok::colon)) { @@ -1855,6 +2176,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, OpenMPVarListDataTy &Data) { UnqualifiedId UnqualifiedReductionId; bool InvalidReductionId = false; + bool IsInvalidMapperModifier = false; // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); @@ -1870,11 +2192,11 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Kind == OMPC_in_reduction) { ColonProtectionRAIIObject ColonRAII(*this); if (getLangOpts().CPlusPlus) - ParseOptionalCXXScopeSpecifier(Data.ReductionIdScopeSpec, + ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec, /*ObjectType=*/nullptr, /*EnteringContext=*/false); - InvalidReductionId = ParseReductionId(*this, Data.ReductionIdScopeSpec, - UnqualifiedReductionId); + InvalidReductionId = ParseReductionId( + *this, Data.ReductionOrMapperIdScopeSpec, UnqualifiedReductionId); if (InvalidReductionId) { SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -1884,7 +2206,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, else Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier"; if (!InvalidReductionId) - Data.ReductionId = + Data.ReductionOrMapperId = Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId); } else if (Kind == OMPC_depend) { // Handle dependency type for depend clause. @@ -1943,8 +2265,11 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, // Only parse map-type-modifier[s] and map-type if a colon is present in // the map clause. if (ColonPresent) { - parseMapTypeModifiers(*this, Data); - parseMapType(*this, Data); + IsInvalidMapperModifier = parseMapTypeModifiers(Data); + if (!IsInvalidMapperModifier) + parseMapType(*this, Data); + else + SkipUntil(tok::colon, tok::annot_pragma_openmp_end, StopBeforeMatch); } if (Data.MapType == OMPC_MAP_unknown) { Data.MapType = OMPC_MAP_tofrom; @@ -1953,6 +2278,60 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, if (Tok.is(tok::colon)) Data.ColonLoc = ConsumeToken(); + } else if (Kind == OMPC_to || Kind == OMPC_from) { + if (Tok.is(tok::identifier)) { + bool IsMapperModifier = false; + if (Kind == OMPC_to) { + auto Modifier = static_cast<OpenMPToModifierKind>( + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok))); + if (Modifier == OMPC_TO_MODIFIER_mapper) + IsMapperModifier = true; + } else { + auto Modifier = static_cast<OpenMPFromModifierKind>( + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok))); + if (Modifier == OMPC_FROM_MODIFIER_mapper) + IsMapperModifier = true; + } + if (IsMapperModifier) { + // Parse the mapper modifier. + ConsumeToken(); + IsInvalidMapperModifier = parseMapperModifier(Data); + if (Tok.isNot(tok::colon)) { + if (!IsInvalidMapperModifier) + Diag(Tok, diag::warn_pragma_expected_colon) << ")"; + SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } + // Consume ':'. + if (Tok.is(tok::colon)) + ConsumeToken(); + } + } + } else if (Kind == OMPC_allocate) { + // Handle optional allocator expression followed by colon delimiter. + ColonProtectionRAIIObject ColonRAII(*this); + TentativeParsingAction TPA(*this); + ExprResult Tail = + Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + Tail = Actions.ActOnFinishFullExpr(Tail.get(), T.getOpenLocation(), + /*DiscardedValue=*/false); + if (Tail.isUsable()) { + if (Tok.is(tok::colon)) { + Data.TailExpr = Tail.get(); + Data.ColonLoc = ConsumeToken(); + TPA.Commit(); + } else { + // colon not found, no allocator specified, parse only list of + // variables. + TPA.Revert(); + } + } else { + // Parsing was unsuccessfull, revert and skip to the end of clause or + // directive. + TPA.Revert(); + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } } bool IsComma = @@ -2013,7 +2392,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, return (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown && Vars.empty()) || (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) || - (MustHaveTail && !Data.TailExpr) || InvalidReductionId; + (MustHaveTail && !Data.TailExpr) || InvalidReductionId || + IsInvalidMapperModifier; } /// Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate', @@ -2046,15 +2426,18 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, /// 'depend' '(' in | out | inout : list | source ')' /// map-clause: /// 'map' '(' [ [ always [,] ] [ close [,] ] +/// [ mapper '(' mapper-identifier ')' [,] ] /// to | from | tofrom | alloc | release | delete ':' ] list ')'; /// to-clause: -/// 'to' '(' list ')' +/// 'to' '(' [ mapper '(' mapper-identifier ')' ':' ] list ')' /// from-clause: -/// 'from' '(' list ')' +/// 'from' '(' [ mapper '(' mapper-identifier ')' ':' ] list ')' /// use_device_ptr-clause: /// 'use_device_ptr' '(' list ')' /// is_device_ptr-clause: /// 'is_device_ptr' '(' list ')' +/// allocate-clause: +/// 'allocate' '(' [ allocator ':' ] list ')' /// /// For 'linear' clause linear-list may have the following forms: /// list @@ -2073,10 +2456,11 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, if (ParseOnly) return nullptr; + OMPVarListLocTy Locs(Loc, LOpen, Data.RLoc); return Actions.ActOnOpenMPVarListClause( - Kind, Vars, Data.TailExpr, Loc, LOpen, Data.ColonLoc, Data.RLoc, - Data.ReductionIdScopeSpec, Data.ReductionId, Data.DepKind, Data.LinKind, - Data.MapTypeModifiers, Data.MapTypeModifiersLoc, Data.MapType, - Data.IsMapTypeImplicit, Data.DepLinMapLoc); + Kind, Vars, Data.TailExpr, Locs, Data.ColonLoc, + Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId, Data.DepKind, + Data.LinKind, Data.MapTypeModifiers, Data.MapTypeModifiersLoc, + Data.MapType, Data.IsMapTypeImplicit, Data.DepLinMapLoc); } diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index 380eb64997a71..f81ecc738c283 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -1,9 +1,8 @@ //===--- ParsePragma.cpp - Language specific pragma parsing ---------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -27,71 +26,72 @@ namespace { struct PragmaAlignHandler : public PragmaHandler { explicit PragmaAlignHandler() : PragmaHandler("align") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaGCCVisibilityHandler : public PragmaHandler { explicit PragmaGCCVisibilityHandler() : PragmaHandler("visibility") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaOptionsHandler : public PragmaHandler { explicit PragmaOptionsHandler() : PragmaHandler("options") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaPackHandler : public PragmaHandler { explicit PragmaPackHandler() : PragmaHandler("pack") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaClangSectionHandler : public PragmaHandler { explicit PragmaClangSectionHandler(Sema &S) : PragmaHandler("section"), Actions(S) {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; + private: Sema &Actions; }; struct PragmaMSStructHandler : public PragmaHandler { explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaUnusedHandler : public PragmaHandler { PragmaUnusedHandler() : PragmaHandler("unused") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaWeakHandler : public PragmaHandler { explicit PragmaWeakHandler() : PragmaHandler("weak") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaRedefineExtnameHandler : public PragmaHandler { explicit PragmaRedefineExtnameHandler() : PragmaHandler("redefine_extname") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaOpenCLExtensionHandler : public PragmaHandler { PragmaOpenCLExtensionHandler() : PragmaHandler("EXTENSION") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaFPContractHandler : public PragmaHandler { PragmaFPContractHandler() : PragmaHandler("FP_CONTRACT") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; @@ -101,7 +101,7 @@ struct PragmaFPContractHandler : public PragmaHandler { struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler { PragmaSTDC_FENV_ACCESSHandler() : PragmaHandler("FENV_ACCESS") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { tok::OnOffSwitch OOS; if (PP.LexOnOffSwitch(OOS)) @@ -118,7 +118,8 @@ struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler { Toks[0].setAnnotationEndLoc(Tok.getLocation()); Toks[0].setAnnotationValue(reinterpret_cast<void*>( static_cast<uintptr_t>(OOS))); - PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } }; @@ -126,7 +127,7 @@ struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler { struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler { PragmaSTDC_CX_LIMITED_RANGEHandler() : PragmaHandler("CX_LIMITED_RANGE") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { tok::OnOffSwitch OOS; PP.LexOnOffSwitch(OOS); @@ -137,7 +138,7 @@ struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler { struct PragmaSTDC_UnknownHandler : public PragmaHandler { PragmaSTDC_UnknownHandler() = default; - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &UnknownTok) override { // C99 6.10.6p2, unknown forms are not allowed. PP.Diag(UnknownTok, diag::ext_stdc_pragma_ignored); @@ -146,19 +147,19 @@ struct PragmaSTDC_UnknownHandler : public PragmaHandler { struct PragmaFPHandler : public PragmaHandler { PragmaFPHandler() : PragmaHandler("fp") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaNoOpenMPHandler : public PragmaHandler { PragmaNoOpenMPHandler() : PragmaHandler("omp") { } - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaOpenMPHandler : public PragmaHandler { PragmaOpenMPHandler() : PragmaHandler("omp") { } - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; @@ -166,8 +167,9 @@ struct PragmaOpenMPHandler : public PragmaHandler { struct PragmaCommentHandler : public PragmaHandler { PragmaCommentHandler(Sema &Actions) : PragmaHandler("comment"), Actions(Actions) {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; + private: Sema &Actions; }; @@ -175,27 +177,28 @@ private: struct PragmaDetectMismatchHandler : public PragmaHandler { PragmaDetectMismatchHandler(Sema &Actions) : PragmaHandler("detect_mismatch"), Actions(Actions) {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; + private: Sema &Actions; }; struct PragmaMSPointersToMembers : public PragmaHandler { explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaMSVtorDisp : public PragmaHandler { explicit PragmaMSVtorDisp() : PragmaHandler("vtordisp") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaMSPragma : public PragmaHandler { explicit PragmaMSPragma(const char *name) : PragmaHandler(name) {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; @@ -203,21 +206,22 @@ struct PragmaMSPragma : public PragmaHandler { struct PragmaOptimizeHandler : public PragmaHandler { PragmaOptimizeHandler(Sema &S) : PragmaHandler("optimize"), Actions(S) {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; + private: Sema &Actions; }; struct PragmaLoopHintHandler : public PragmaHandler { PragmaLoopHintHandler() : PragmaHandler("loop") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaUnrollHintHandler : public PragmaHandler { PragmaUnrollHintHandler(const char *name) : PragmaHandler(name) {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; @@ -227,20 +231,20 @@ struct PragmaMSRuntimeChecksHandler : public EmptyPragmaHandler { struct PragmaMSIntrinsicHandler : public PragmaHandler { PragmaMSIntrinsicHandler() : PragmaHandler("intrinsic") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaMSOptimizeHandler : public PragmaHandler { PragmaMSOptimizeHandler() : PragmaHandler("optimize") {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; }; struct PragmaForceCUDAHostDeviceHandler : public PragmaHandler { PragmaForceCUDAHostDeviceHandler(Sema &Actions) : PragmaHandler("force_cuda_host_device"), Actions(Actions) {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; private: @@ -251,7 +255,7 @@ private: struct PragmaAttributeHandler : public PragmaHandler { PragmaAttributeHandler(AttributeFactory &AttrFactory) : PragmaHandler("attribute"), AttributesForPragmaAttribute(AttrFactory) {} - void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) override; /// A pool of attributes that were parsed in \#pragma clang attribute. @@ -693,13 +697,12 @@ void Parser::HandlePragmaOpenCLExtension() { if (Name == "all") { if (State == Disable) { Opt.disableAll(); - Opt.enableSupportedCore(getLangOpts().OpenCLVersion); + Opt.enableSupportedCore(getLangOpts()); } else { PP.Diag(NameLoc, diag::warn_pragma_expected_predicate) << 1; } } else if (State == Begin) { - if (!Opt.isKnown(Name) || - !Opt.isSupported(Name, getLangOpts().OpenCLVersion)) { + if (!Opt.isKnown(Name) || !Opt.isSupported(Name, getLangOpts())) { Opt.support(Name); } Actions.setCurrentOpenCLExtension(Name); @@ -709,9 +712,9 @@ void Parser::HandlePragmaOpenCLExtension() { Actions.setCurrentOpenCLExtension(""); } else if (!Opt.isKnown(Name)) PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << Ident; - else if (Opt.isSupportedExtension(Name, getLangOpts().OpenCLVersion)) + else if (Opt.isSupportedExtension(Name, getLangOpts())) Opt.enable(Name, State == Enable); - else if (Opt.isSupportedCore(Name, getLangOpts().OpenCLVersion)) + else if (Opt.isSupportedCore(Name, getLangOpts())) PP.Diag(NameLoc, diag::warn_pragma_extension_is_core) << Ident; else PP.Diag(NameLoc, diag::warn_pragma_unsupported_extension) << Ident; @@ -741,7 +744,8 @@ void Parser::HandlePragmaMSPragma() { // Grab the tokens out of the annotation and enter them into the stream. auto TheTokens = (std::pair<std::unique_ptr<Token[]>, size_t> *)Tok.getAnnotationValue(); - PP.EnterTokenStream(std::move(TheTokens->first), TheTokens->second, true); + PP.EnterTokenStream(std::move(TheTokens->first), TheTokens->second, true, + /*IsReinject=*/true); SourceLocation PragmaLocation = ConsumeAnnotationToken(); assert(Tok.isAnyIdentifier()); StringRef PragmaName = Tok.getIdentifierInfo()->getName(); @@ -1113,7 +1117,8 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) { Hint.StateLoc = IdentifierLoc::create(Actions.Context, StateLoc, StateInfo); } else { // Enter constant expression including eof terminator into token stream. - PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/false); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/false, + /*IsReinject=*/false); ConsumeAnnotationToken(); ExprResult R = ParseConstantExpression(); @@ -1416,7 +1421,8 @@ void Parser::HandlePragmaAttribute() { return; } - PP.EnterTokenStream(Info->Tokens, /*DisableMacroExpansion=*/false); + PP.EnterTokenStream(Info->Tokens, /*DisableMacroExpansion=*/false, + /*IsReinject=*/false); ConsumeAnnotationToken(); ParsedAttributes &Attrs = Info->Attributes; @@ -1574,7 +1580,7 @@ void Parser::HandlePragmaAttribute() { // 'push' '(' [visibility] ')' // 'pop' void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &VisTok) { SourceLocation VisLoc = VisTok.getLocation(); @@ -1625,8 +1631,9 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, Toks[0].setLocation(VisLoc); Toks[0].setAnnotationEndLoc(EndLoc); Toks[0].setAnnotationValue( - const_cast<void*>(static_cast<const void*>(VisType))); - PP.EnterTokenStream(std::move(Toks), 1, /*DisableMacroExpansion=*/true); + const_cast<void *>(static_cast<const void *>(VisType))); + PP.EnterTokenStream(std::move(Toks), 1, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } // #pragma pack(...) comes in the following delicious flavors: @@ -1634,7 +1641,7 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, // pack '(' 'show' ')' // pack '(' ('push' | 'pop') [',' identifier] [, integer] ')' void PragmaPackHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &PackTok) { SourceLocation PackLoc = PackTok.getLocation(); @@ -1739,13 +1746,14 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Toks[0].setLocation(PackLoc); Toks[0].setAnnotationEndLoc(RParenLoc); Toks[0].setAnnotationValue(static_cast<void*>(Info)); - PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } // #pragma ms_struct on // #pragma ms_struct off void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &MSStructTok) { PragmaMSStructKind Kind = PMSST_OFF; @@ -1782,12 +1790,14 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, Toks[0].setAnnotationEndLoc(EndLoc); Toks[0].setAnnotationValue(reinterpret_cast<void*>( static_cast<uintptr_t>(Kind))); - PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } // #pragma clang section bss="abc" data="" rodata="def" text="" void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, Token &FirstToken) { + PragmaIntroducer Introducer, + Token &FirstToken) { Token Tok; auto SecKind = Sema::PragmaClangSectionKind::PCSK_Invalid; @@ -1895,24 +1905,25 @@ static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok, Toks[0].setAnnotationEndLoc(EndLoc); Toks[0].setAnnotationValue(reinterpret_cast<void*>( static_cast<uintptr_t>(Kind))); - PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } void PragmaAlignHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &AlignTok) { ParseAlignPragma(PP, AlignTok, /*IsOptions=*/false); } void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &OptionsTok) { ParseAlignPragma(PP, OptionsTok, /*IsOptions=*/true); } // #pragma unused(identifier) void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &UnusedTok) { // FIXME: Should we be expanding macros here? My guess is no. SourceLocation UnusedLoc = UnusedTok.getLocation(); @@ -1987,13 +1998,14 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, pragmaUnusedTok.setLocation(UnusedLoc); idTok = Identifiers[i]; } - PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } // #pragma weak identifier // #pragma weak identifier '=' identifier void PragmaWeakHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &WeakTok) { SourceLocation WeakLoc = WeakTok.getLocation(); @@ -2036,7 +2048,8 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, pragmaUnusedTok.setAnnotationEndLoc(AliasName.getLocation()); Toks[1] = WeakName; Toks[2] = AliasName; - PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } else { MutableArrayRef<Token> Toks( PP.getPreprocessorAllocator().Allocate<Token>(2), 2); @@ -2046,13 +2059,14 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, pragmaUnusedTok.setLocation(WeakLoc); pragmaUnusedTok.setAnnotationEndLoc(WeakLoc); Toks[1] = WeakName; - PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } } // #pragma redefine_extname identifier identifier void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &RedefToken) { SourceLocation RedefLoc = RedefToken.getLocation(); @@ -2091,14 +2105,13 @@ void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP, pragmaRedefTok.setAnnotationEndLoc(AliasName.getLocation()); Toks[1] = RedefName; Toks[2] = AliasName; - PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } - -void -PragmaFPContractHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, - Token &Tok) { +void PragmaFPContractHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducer Introducer, + Token &Tok) { tok::OnOffSwitch OOS; if (PP.LexOnOffSwitch(OOS)) return; @@ -2111,13 +2124,13 @@ PragmaFPContractHandler::HandlePragma(Preprocessor &PP, Toks[0].setAnnotationEndLoc(Tok.getLocation()); Toks[0].setAnnotationValue(reinterpret_cast<void*>( static_cast<uintptr_t>(OOS))); - PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } -void -PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, - Token &Tok) { +void PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducer Introducer, + Token &Tok) { PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::identifier)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << @@ -2173,7 +2186,8 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, Toks[0].setLocation(NameLoc); Toks[0].setAnnotationValue(static_cast<void*>(Info)); Toks[0].setAnnotationEndLoc(StateLoc); - PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); if (PP.getPPCallbacks()) PP.getPPCallbacks()->PragmaOpenCLExtension(NameLoc, Ext, @@ -2182,10 +2196,9 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, /// Handle '#pragma omp ...' when OpenMP is disabled. /// -void -PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, - Token &FirstTok) { +void PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducer Introducer, + Token &FirstTok) { if (!PP.getDiagnostics().isIgnored(diag::warn_pragma_omp_ignored, FirstTok.getLocation())) { PP.Diag(FirstTok, diag::warn_pragma_omp_ignored); @@ -2197,15 +2210,14 @@ PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP, /// Handle '#pragma omp ...' when OpenMP is enabled. /// -void -PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, - Token &FirstTok) { +void PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducer Introducer, + Token &FirstTok) { SmallVector<Token, 16> Pragma; Token Tok; Tok.startToken(); Tok.setKind(tok::annot_pragma_openmp); - Tok.setLocation(FirstTok.getLocation()); + Tok.setLocation(Introducer.Loc); while (Tok.isNot(tok::eod) && Tok.isNot(tok::eof)) { Pragma.push_back(Tok); @@ -2232,7 +2244,7 @@ PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, auto Toks = llvm::make_unique<Token[]>(Pragma.size()); std::copy(Pragma.begin(), Pragma.end(), Toks.get()); PP.EnterTokenStream(std::move(Toks), Pragma.size(), - /*DisableMacroExpansion=*/false); + /*DisableMacroExpansion=*/false, /*IsReinject=*/false); } /// Handle '#pragma pointers_to_members' @@ -2244,7 +2256,7 @@ PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, // #pragma pointers_to_members '(' 'full_generality' [',' inheritance-model] ')' // #pragma pointers_to_members '(' inheritance-model ')' void PragmaMSPointersToMembers::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &Tok) { SourceLocation PointersToMembersLoc = Tok.getLocation(); PP.Lex(Tok); @@ -2330,7 +2342,7 @@ void PragmaMSPointersToMembers::HandlePragma(Preprocessor &PP, AnnotTok.setAnnotationEndLoc(EndLoc); AnnotTok.setAnnotationValue( reinterpret_cast<void *>(static_cast<uintptr_t>(RepresentationMethod))); - PP.EnterToken(AnnotTok); + PP.EnterToken(AnnotTok, /*IsReinject=*/true); } /// Handle '#pragma vtordisp' @@ -2342,8 +2354,7 @@ void PragmaMSPointersToMembers::HandlePragma(Preprocessor &PP, // #pragma vtordisp '(' 'pop' ')' // #pragma vtordisp '(' ')' void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, - Token &Tok) { + PragmaIntroducer Introducer, Token &Tok) { SourceLocation VtorDispLoc = Tok.getLocation(); PP.Lex(Tok); if (Tok.isNot(tok::l_paren)) { @@ -2423,14 +2434,13 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP, AnnotTok.setAnnotationEndLoc(EndLoc); AnnotTok.setAnnotationValue(reinterpret_cast<void *>( static_cast<uintptr_t>((Action << 16) | (Value & 0xFFFF)))); - PP.EnterToken(AnnotTok); + PP.EnterToken(AnnotTok, /*IsReinject=*/false); } /// Handle all MS pragmas. Simply forwards the tokens after inserting /// an annotation token. void PragmaMSPragma::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, - Token &Tok) { + PragmaIntroducer Introducer, Token &Tok) { Token EoF, AnnotTok; EoF.startToken(); EoF.setKind(tok::eof); @@ -2454,7 +2464,7 @@ void PragmaMSPragma::HandlePragma(Preprocessor &PP, std::pair<std::unique_ptr<Token[]>, size_t>(std::move(TokenArray), TokenVector.size()); AnnotTok.setAnnotationValue(Value); - PP.EnterToken(AnnotTok); + PP.EnterToken(AnnotTok, /*IsReinject*/ false); } /// Handle the Microsoft \#pragma detect_mismatch extension. @@ -2468,7 +2478,7 @@ void PragmaMSPragma::HandlePragma(Preprocessor &PP, /// mismatch in the object file's values for the given name, a LNK2038 error /// is emitted. See MSDN for more details. void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &Tok) { SourceLocation DetectMismatchLoc = Tok.getLocation(); PP.Lex(Tok); @@ -2481,7 +2491,7 @@ void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP, std::string NameString; if (!PP.LexStringLiteral(Tok, NameString, "pragma detect_mismatch", - /*MacroExpansion=*/true)) + /*AllowMacroExpansion=*/true)) return; // Read the comma followed by a second string literal. @@ -2492,7 +2502,7 @@ void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP, } if (!PP.LexStringLiteral(Tok, ValueString, "pragma detect_mismatch", - /*MacroExpansion=*/true)) + /*AllowMacroExpansion=*/true)) return; if (Tok.isNot(tok::r_paren)) { @@ -2524,7 +2534,7 @@ void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP, /// "foo" is a string, which is fully macro expanded, and permits string /// concatenation, embedded escape characters etc. See MSDN for more details. void PragmaCommentHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &Tok) { SourceLocation CommentLoc = Tok.getLocation(); PP.Lex(Tok); @@ -2574,7 +2584,7 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, std::string ArgumentString; if (Tok.is(tok::comma) && !PP.LexStringLiteral(Tok, ArgumentString, "pragma comment", - /*MacroExpansion=*/true)) + /*AllowMacroExpansion=*/true)) return; // FIXME: warn that 'exestr' is deprecated. @@ -2605,8 +2615,8 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, // #pragma clang optimize off // #pragma clang optimize on void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, - Token &FirstToken) { + PragmaIntroducer Introducer, + Token &FirstToken) { Token Tok; PP.Lex(Tok); if (Tok.is(tok::eod)) { @@ -2652,8 +2662,7 @@ struct TokFPAnnotValue { } // end anonymous namespace void PragmaFPHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, - Token &Tok) { + PragmaIntroducer Introducer, Token &Tok) { // fp Token PragmaName = Tok; SmallVector<Token, 1> TokenList; @@ -2738,7 +2747,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP, std::copy(TokenList.begin(), TokenList.end(), TokenArray.get()); PP.EnterTokenStream(std::move(TokenArray), TokenList.size(), - /*DisableMacroExpansion=*/false); + /*DisableMacroExpansion=*/false, /*IsReinject=*/false); } void Parser::HandlePragmaFP() { @@ -2853,7 +2862,7 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName, /// loop. Specifying unroll_count(_value_) instructs llvm to try to unroll the /// loop the number of times indicated by the value. void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &Tok) { // Incoming token is "loop" from "#pragma clang loop". Token PragmaName = Tok; @@ -2921,7 +2930,7 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, std::copy(TokenList.begin(), TokenList.end(), TokenArray.get()); PP.EnterTokenStream(std::move(TokenArray), TokenList.size(), - /*DisableMacroExpansion=*/false); + /*DisableMacroExpansion=*/false, /*IsReinject=*/false); } /// Handle the loop unroll optimization pragmas. @@ -2946,7 +2955,7 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, /// specified with or without parentheses. Specifying, '#pragma nounroll' /// disables unrolling of the loop. void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &Tok) { // Incoming token is "unroll" for "#pragma unroll", or "nounroll" for // "#pragma nounroll". @@ -2996,7 +3005,7 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP, TokenArray[0].setAnnotationEndLoc(PragmaName.getLocation()); TokenArray[0].setAnnotationValue(static_cast<void *>(Info)); PP.EnterTokenStream(std::move(TokenArray), 1, - /*DisableMacroExpansion=*/false); + /*DisableMacroExpansion=*/false, /*IsReinject=*/false); } /// Handle the Microsoft \#pragma intrinsic extension. @@ -3012,7 +3021,7 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP, /// 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, + PragmaIntroducer Introducer, Token &Tok) { PP.Lex(Tok); @@ -3051,7 +3060,7 @@ void PragmaMSIntrinsicHandler::HandlePragma(Preprocessor &PP, // #pragma optimize("gsty", on|off) void PragmaMSOptimizeHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &Tok) { SourceLocation StartLoc = Tok.getLocation(); PP.Lex(Tok); @@ -3104,7 +3113,7 @@ void PragmaMSOptimizeHandler::HandlePragma(Preprocessor &PP, } void PragmaForceCUDAHostDeviceHandler::HandlePragma( - Preprocessor &PP, PragmaIntroducerKind Introducer, Token &Tok) { + Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) { Token FirstTok = Tok; PP.Lex(Tok); @@ -3155,7 +3164,7 @@ void PragmaForceCUDAHostDeviceHandler::HandlePragma( /// attribute to the set of attribute-specific declarations in the active range /// of the pragma. void PragmaAttributeHandler::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, + PragmaIntroducer Introducer, Token &FirstToken) { Token Tok; PP.Lex(Tok); @@ -3268,5 +3277,5 @@ void PragmaAttributeHandler::HandlePragma(Preprocessor &PP, TokenArray[0].setAnnotationEndLoc(FirstToken.getLocation()); TokenArray[0].setAnnotationValue(static_cast<void *>(Info)); PP.EnterTokenStream(std::move(TokenArray), 1, - /*DisableMacroExpansion=*/false); + /*DisableMacroExpansion=*/false, /*IsReinject=*/false); } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 2974e6a245b0e..bf04253ab7fdc 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1,9 +1,8 @@ //===--- ParseStmt.cpp - Statement and Block Parser -----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -30,17 +29,14 @@ using namespace clang; /// Parse a standalone statement (for instance, as the body of an 'if', /// 'while', or 'for'). StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc, - bool AllowOpenMPStandalone) { + ParsedStmtContext StmtCtx) { StmtResult Res; // We may get back a null statement if we found a #pragma. Keep going until // we get an actual statement. do { StmtVector Stmts; - Res = ParseStatementOrDeclaration( - Stmts, AllowOpenMPStandalone ? ACK_StatementsOpenMPAnyExecutable - : ACK_StatementsOpenMPNonStandalone, - TrailingElseLoc); + Res = ParseStatementOrDeclaration(Stmts, StmtCtx, TrailingElseLoc); } while (!Res.isInvalid() && !Res.get()); return Res; @@ -97,7 +93,7 @@ StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc, /// StmtResult Parser::ParseStatementOrDeclaration(StmtVector &Stmts, - AllowedConstructsKind Allowed, + ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc) { ParenBraceBracketBalancer BalancerRAIIObj(*this); @@ -108,7 +104,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, return StmtError(); StmtResult Res = ParseStatementOrDeclarationAfterAttributes( - Stmts, Allowed, TrailingElseLoc, Attrs); + Stmts, StmtCtx, TrailingElseLoc, Attrs); assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) && "attributes on empty statement"); @@ -120,7 +116,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, } namespace { -class StatementFilterCCC : public CorrectionCandidateCallback { +class StatementFilterCCC final : public CorrectionCandidateCallback { public: StatementFilterCCC(Token nextTok) : NextToken(nextTok) { WantTypeSpecifiers = nextTok.isOneOf(tok::l_paren, tok::less, tok::l_square, @@ -143,15 +139,18 @@ public: return CorrectionCandidateCallback::ValidateCandidate(candidate); } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<StatementFilterCCC>(*this); + } + private: Token NextToken; }; } -StmtResult -Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts, - AllowedConstructsKind Allowed, SourceLocation *TrailingElseLoc, - ParsedAttributesWithRange &Attrs) { +StmtResult Parser::ParseStatementOrDeclarationAfterAttributes( + StmtVector &Stmts, ParsedStmtContext StmtCtx, + SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) { const char *SemiError = nullptr; StmtResult Res; @@ -166,7 +165,7 @@ Retry: { ProhibitAttributes(Attrs); // TODO: is it correct? AtLoc = ConsumeToken(); // consume @ - return ParseObjCAtStatement(AtLoc); + return ParseObjCAtStatement(AtLoc, StmtCtx); } case tok::code_completion: @@ -178,7 +177,7 @@ Retry: Token Next = NextToken(); if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement - return ParseLabeledStatement(Attrs); + return ParseLabeledStatement(Attrs, StmtCtx); } // Look up the identifier, and typo-correct it to a keyword if it's not @@ -186,9 +185,8 @@ Retry: if (Next.isNot(tok::coloncolon)) { // Try to limit which sets of keywords should be included in typo // correction based on what the next token is. - if (TryAnnotateName(/*IsAddressOfOperand*/ false, - llvm::make_unique<StatementFilterCCC>(Next)) == - ANK_Error) { + StatementFilterCCC CCC(Next); + if (TryAnnotateName(/*IsAddressOfOperand*/ false, &CCC) == ANK_Error) { // Handle errors here by skipping up to the next semicolon or '}', and // eat the semicolon if that's what stopped us. SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); @@ -208,7 +206,8 @@ Retry: default: { if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || - Allowed == ACK_Any) && + (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != + ParsedStmtContext()) && isDeclarationStatement()) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl = ParseDeclaration(DeclaratorContext::BlockContext, @@ -221,13 +220,13 @@ Retry: return StmtError(); } - return ParseExprStatement(); + return ParseExprStatement(StmtCtx); } case tok::kw_case: // C99 6.8.1: labeled-statement - return ParseCaseStatement(); + return ParseCaseStatement(StmtCtx); case tok::kw_default: // C99 6.8.1: labeled-statement - return ParseDefaultStatement(); + return ParseDefaultStatement(StmtCtx); case tok::l_brace: // C99 6.8.2: compound-statement return ParseCompoundStatement(); @@ -364,7 +363,7 @@ Retry: case tok::annot_pragma_openmp: ProhibitAttributes(Attrs); - return ParseOpenMPDeclarativeOrExecutableDirective(Allowed); + return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx); case tok::annot_pragma_ms_pointers_to_members: ProhibitAttributes(Attrs); @@ -383,7 +382,7 @@ Retry: case tok::annot_pragma_loop_hint: ProhibitAttributes(Attrs); - return ParsePragmaLoopHint(Stmts, Allowed, TrailingElseLoc, Attrs); + return ParsePragmaLoopHint(Stmts, StmtCtx, TrailingElseLoc, Attrs); case tok::annot_pragma_dump: HandlePragmaDump(); @@ -408,7 +407,7 @@ Retry: } /// Parse an expression statement. -StmtResult Parser::ParseExprStatement() { +StmtResult Parser::ParseExprStatement(ParsedStmtContext StmtCtx) { // If a case keyword is missing, this is where it should be inserted. Token OldToken = Tok; @@ -434,12 +433,12 @@ StmtResult Parser::ParseExprStatement() { << FixItHint::CreateInsertion(OldToken.getLocation(), "case "); // Recover parsing as a case statement. - return ParseCaseStatement(/*MissingCase=*/true, Expr); + return ParseCaseStatement(StmtCtx, /*MissingCase=*/true, Expr); } // Otherwise, eat the semicolon. ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); - return Actions.ActOnExprStmt(Expr, isExprValueDiscarded()); + return handleExprStmt(Expr, StmtCtx); } /// ParseSEHTryBlockCommon @@ -578,10 +577,15 @@ StmtResult Parser::ParseSEHLeaveStatement() { /// identifier ':' statement /// [GNU] identifier ':' attributes[opt] statement /// -StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) { +StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs, + ParsedStmtContext StmtCtx) { assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && "Not an identifier!"); + // The substatement is always a 'statement', not a 'declaration', but is + // otherwise in the same context as the labeled-statement. + StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC; + Token IdentTok = Tok; // Save the whole token. ConsumeToken(); // eat the identifier. @@ -611,9 +615,8 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) { // statement, but that doesn't work correctly (because ProhibitAttributes // can't handle GNU attributes), so only call it in the one case where // GNU attributes are allowed. - SubStmt = ParseStatementOrDeclarationAfterAttributes( - Stmts, /*Allowed=*/ACK_StatementsOpenMPNonStandalone, nullptr, - TempAttrs); + SubStmt = ParseStatementOrDeclarationAfterAttributes(Stmts, StmtCtx, + nullptr, TempAttrs); if (!TempAttrs.empty() && !SubStmt.isInvalid()) SubStmt = Actions.ProcessStmtAttributes(SubStmt.get(), TempAttrs, TempAttrs.Range); @@ -624,7 +627,7 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) { // If we've not parsed a statement yet, parse one now. if (!SubStmt.isInvalid() && !SubStmt.isUsable()) - SubStmt = ParseStatement(); + SubStmt = ParseStatement(nullptr, StmtCtx); // Broken substmt shouldn't prevent the label from being added to the AST. if (SubStmt.isInvalid()) @@ -644,9 +647,14 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) { /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// -StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) { +StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx, + bool MissingCase, ExprResult Expr) { assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!"); + // The substatement is always a 'statement', not a 'declaration', but is + // otherwise in the same context as the labeled-statement. + StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC; + // It is very very common for code to contain many case statements recursively // nested, as in (but usually without indentation): // case 1: @@ -738,8 +746,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) { // continue parsing the sub-stmt. if (Case.isInvalid()) { if (TopLevelCase.isInvalid()) // No parsed case stmts. - return ParseStatement(/*TrailingElseLoc=*/nullptr, - /*AllowOpenMPStandalone=*/true); + return ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx); // Otherwise, just don't add it as a nested case. } else { // If this is the first case statement we parsed, it becomes TopLevelCase. @@ -759,8 +766,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) { StmtResult SubStmt; if (Tok.isNot(tok::r_brace)) { - SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, - /*AllowOpenMPStandalone=*/true); + SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx); } else { // Nicely diagnose the common error "switch (X) { case 4: }", which is // not valid. If ColonLoc doesn't point to a valid text location, there was @@ -790,8 +796,13 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) { /// 'default' ':' statement /// Note that this does not parse the 'statement' at the end. /// -StmtResult Parser::ParseDefaultStatement() { +StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) { assert(Tok.is(tok::kw_default) && "Not a default stmt!"); + + // The substatement is always a 'statement', not a 'declaration', but is + // otherwise in the same context as the labeled-statement. + StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC; + SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. SourceLocation ColonLoc; @@ -812,8 +823,7 @@ StmtResult Parser::ParseDefaultStatement() { StmtResult SubStmt; if (Tok.isNot(tok::r_brace)) { - SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, - /*AllowOpenMPStandalone=*/true); + SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx); } else { // Diagnose the common error "switch (X) {... default: }", which is // not valid. @@ -944,7 +954,8 @@ bool Parser::ConsumeNullStmt(StmtVector &Stmts) { EndLoc = Tok.getLocation(); // Don't just ConsumeToken() this tok::semi, do store it in AST. - StmtResult R = ParseStatementOrDeclaration(Stmts, ACK_Any); + StmtResult R = + ParseStatementOrDeclaration(Stmts, ParsedStmtContext::SubStmt); if (R.isUsable()) Stmts.push_back(R.get()); } @@ -958,14 +969,24 @@ bool Parser::ConsumeNullStmt(StmtVector &Stmts) { return true; } -bool Parser::isExprValueDiscarded() { - if (Actions.isCurCompoundStmtAStmtExpr()) { - // Look to see if the next two tokens close the statement expression; - // if so, this expression statement is the last statement in a - // statment expression. - return Tok.isNot(tok::r_brace) || NextToken().isNot(tok::r_paren); +StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) { + bool IsStmtExprResult = false; + if ((StmtCtx & ParsedStmtContext::InStmtExpr) != ParsedStmtContext()) { + // For GCC compatibility we skip past NullStmts. + unsigned LookAhead = 0; + while (GetLookAheadToken(LookAhead).is(tok::semi)) { + ++LookAhead; + } + // Then look to see if the next two tokens close the statement expression; + // if so, this expression statement is the last statement in a statment + // expression. + IsStmtExprResult = GetLookAheadToken(LookAhead).is(tok::r_brace) && + GetLookAheadToken(LookAhead + 1).is(tok::r_paren); } - return true; + + if (IsStmtExprResult) + E = Actions.ActOnStmtExprResult(E); + return Actions.ActOnExprStmt(E, /*DiscardedValue=*/!IsStmtExprResult); } /// ParseCompoundStatementBody - Parse a sequence of statements and invoke the @@ -1023,6 +1044,10 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { Stmts.push_back(R.get()); } + ParsedStmtContext SubStmtCtx = + ParsedStmtContext::Compound | + (isStmtExpr ? ParsedStmtContext::InStmtExpr : ParsedStmtContext()); + while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { if (Tok.is(tok::annot_pragma_unused)) { @@ -1035,7 +1060,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { StmtResult R; if (Tok.isNot(tok::kw___extension__)) { - R = ParseStatementOrDeclaration(Stmts, ACK_Any); + R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); } else { // __extension__ can start declarations and it can also be a unary // operator for expressions. Consume multiple __extension__ markers here @@ -1068,11 +1093,12 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { continue; } - // FIXME: Use attributes? // Eat the semicolon at the end of stmt and convert the expr into a // statement. ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); - R = Actions.ActOnExprStmt(Res, isExprValueDiscarded()); + R = handleExprStmt(Res, SubStmtCtx); + if (R.isUsable()) + R = Actions.ProcessStmtAttributes(R.get(), attrs, attrs.Range); } } @@ -1971,9 +1997,12 @@ StmtResult Parser::ParseReturnStatement() { ExprResult R; if (Tok.isNot(tok::semi)) { + if (!IsCoreturn) + PreferredType.enterReturn(Actions, Tok.getLocation()); // FIXME: Code completion for co_return. if (Tok.is(tok::code_completion) && !IsCoreturn) { - Actions.CodeCompleteReturn(getCurScope()); + Actions.CodeCompleteExpression(getCurScope(), + PreferredType.get(Tok.getLocation())); cutOffParsing(); return StmtError(); } @@ -1999,7 +2028,7 @@ StmtResult Parser::ParseReturnStatement() { } StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, - AllowedConstructsKind Allowed, + ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) { // Create temporary attribute list. @@ -2022,7 +2051,7 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, MaybeParseCXX11Attributes(Attrs); StmtResult S = ParseStatementOrDeclarationAfterAttributes( - Stmts, Allowed, TrailingElseLoc, Attrs); + Stmts, StmtCtx, TrailingElseLoc, Attrs); Attrs.takeAllFrom(TempAttrs); return S; @@ -2241,7 +2270,8 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) { // The name in a catch exception-declaration is local to the handler and // shall not be redeclared in the outermost block of the handler. ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope | - (FnCatch ? Scope::FnTryCatchScope : 0)); + Scope::CatchScope | + (FnCatch ? Scope::FnTryCatchScope : 0)); // exception-declaration is equivalent to '...' or a parameter-declaration // without default arguments. @@ -2327,7 +2357,8 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { // Condition is true, parse the statements. while (Tok.isNot(tok::r_brace)) { - StmtResult R = ParseStatementOrDeclaration(Stmts, ACK_Any); + StmtResult R = + ParseStatementOrDeclaration(Stmts, ParsedStmtContext::Compound); if (R.isUsable()) Stmts.push_back(R.get()); } diff --git a/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp index 9b96c5150e569..1153c2510b05d 100644 --- a/lib/Parse/ParseStmtAsm.cpp +++ b/lib/Parse/ParseStmtAsm.cpp @@ -1,9 +1,8 @@ //===---- ParseStmtAsm.cpp - Assembly Statement Parser --------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -145,8 +144,8 @@ void ClangAsmParserCallback::findTokensForString( // Try to find a token whose offset matches the first token. unsigned FirstCharOffset = Str.begin() - AsmString.begin(); - const unsigned *FirstTokOffset = std::lower_bound( - AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset); + const unsigned *FirstTokOffset = + llvm::lower_bound(AsmTokOffsets, FirstCharOffset); // For now, assert that the start of the string exactly // corresponds to the start of a token. @@ -175,8 +174,7 @@ ClangAsmParserCallback::translateLocation(const llvm::SourceMgr &LSM, unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart(); // Figure out which token that offset points into. - const unsigned *TokOffsetPtr = - std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset); + const unsigned *TokOffsetPtr = llvm::lower_bound(AsmTokOffsets, Offset); unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin(); unsigned TokOffset = *TokOffsetPtr; @@ -214,7 +212,8 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, // Also copy the current token over. LineToks.push_back(Tok); - PP.EnterTokenStream(LineToks, /*DisableMacroExpansions*/ true); + PP.EnterTokenStream(LineToks, /*DisableMacroExpansions*/ true, + /*IsReinject*/ true); // Clear the current token and advance to the first token in LineToks. ConsumeAnyToken(); @@ -637,7 +636,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { // Filter out "fpsw" and "mxcsr". They aren't valid GCC asm clobber // constraints. Clang always adds fpsr to the clobber list anyway. llvm::erase_if(Clobbers, [](const std::string &C) { - return C == "fpsw" || C == "mxcsr"; + return C == "fpsr" || C == "mxcsr"; }); // Build the vector of clobber StringRefs. @@ -710,12 +709,12 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { // Remember if this was a volatile asm. bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; + // Remember if this was a goto asm. + bool isGotoAsm = false; - // TODO: support "asm goto" constructs (PR#9295). if (Tok.is(tok::kw_goto)) { - Diag(Tok, diag::err_asm_goto_not_supported_yet); - SkipUntil(tok::r_paren, StopAtSemi); - return StmtError(); + isGotoAsm = true; + ConsumeToken(); } if (Tok.isNot(tok::l_paren)) { @@ -753,7 +752,8 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr, Constraints, Exprs, AsmString.get(), - Clobbers, T.getCloseLocation()); + Clobbers, /*NumLabels*/ 0, + T.getCloseLocation()); } // Parse Outputs, if present. @@ -763,6 +763,12 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { AteExtraColon = Tok.is(tok::coloncolon); ConsumeToken(); + if (!AteExtraColon && isGotoAsm && Tok.isNot(tok::colon)) { + Diag(Tok, diag::err_asm_goto_cannot_have_output); + SkipUntil(tok::r_paren, StopAtSemi); + return StmtError(); + } + if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs)) return StmtError(); } @@ -789,12 +795,15 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { unsigned NumInputs = Names.size() - NumOutputs; // Parse the clobbers, if present. - if (AteExtraColon || Tok.is(tok::colon)) { - if (!AteExtraColon) + if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { + if (AteExtraColon) + AteExtraColon = false; + else { + AteExtraColon = Tok.is(tok::coloncolon); ConsumeToken(); - + } // Parse the asm-string list for clobbers if present. - if (Tok.isNot(tok::r_paren)) { + if (!AteExtraColon && isTokenStringLiteral()) { while (1) { ExprResult Clobber(ParseAsmStringLiteral()); @@ -808,11 +817,49 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { } } } + if (!isGotoAsm && (Tok.isNot(tok::r_paren) || AteExtraColon)) { + Diag(Tok, diag::err_expected) << tok::r_paren; + SkipUntil(tok::r_paren, StopAtSemi); + return StmtError(); + } + // Parse the goto label, if present. + unsigned NumLabels = 0; + if (AteExtraColon || Tok.is(tok::colon)) { + if (!AteExtraColon) + ConsumeToken(); + + while (true) { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected) << tok::identifier; + SkipUntil(tok::r_paren, StopAtSemi); + return StmtError(); + } + LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(), + Tok.getLocation()); + Names.push_back(Tok.getIdentifierInfo()); + if (!LD) { + SkipUntil(tok::r_paren, StopAtSemi); + return StmtError(); + } + ExprResult Res = + Actions.ActOnAddrLabel(Tok.getLocation(), Tok.getLocation(), LD); + Exprs.push_back(Res.get()); + NumLabels++; + ConsumeToken(); + if (!TryConsumeToken(tok::comma)) + break; + } + } else if (isGotoAsm) { + Diag(Tok, diag::err_expected) << tok::colon; + SkipUntil(tok::r_paren, StopAtSemi); + return StmtError(); + } T.consumeClose(); return Actions.ActOnGCCAsmStmt( AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(), - Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation()); + Constraints, Exprs, AsmString.get(), Clobbers, NumLabels, + T.getCloseLocation()); } /// ParseAsmOperands - Parse the asm-operands production as used by diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index e0a7cc6e856db..9bb5b6eac37e2 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -1,9 +1,8 @@ //===--- ParseTemplate.cpp - Template Parsing -----------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -19,6 +18,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" +#include "llvm/Support/TimeProfiler.h" using namespace clang; /// Parse a template declaration, explicit instantiation, or @@ -49,6 +49,15 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( /// template-declaration: [C++ temp] /// 'export'[opt] 'template' '<' template-parameter-list '>' declaration /// +/// template-declaration: [C++2a] +/// template-head declaration +/// template-head concept-definition +/// +/// TODO: requires-clause +/// template-head: [C++2a] +/// 'template' '<' template-parameter-list '>' +/// requires-clause[opt] +/// /// explicit-specialization: [ C++ temp.expl.spec] /// 'template' '<' '>' declaration Decl *Parser::ParseTemplateDeclarationOrSpecialization( @@ -142,6 +151,12 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization); // Parse the actual template declaration. + if (Tok.is(tok::kw_concept)) + return ParseConceptDefinition( + ParsedTemplateInfo(&ParamLists, isSpecialization, + LastParamListWasEmpty), + DeclEnd); + return ParseSingleDeclarationAfterTemplate( Context, ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty), @@ -232,6 +247,12 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( return nullptr; } + llvm::TimeTraceScope TimeScope("ParseTemplate", [&]() { + return DeclaratorInfo.getIdentifier() != nullptr + ? DeclaratorInfo.getIdentifier()->getName() + : "<unknown>"; + }); + LateParsedAttrList LateParsedAttrs(true); if (DeclaratorInfo.isFunctionDeclarator()) MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); @@ -282,7 +303,7 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( return ParseFunctionDefinition( DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists, /*isSpecialization=*/true, - /*LastParamListWasEmpty=*/true), + /*lastParameterListWasEmpty=*/true), &LateParsedAttrs); } } @@ -309,6 +330,85 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( return ThisDecl; } +/// \brief Parse a single declaration that declares a concept. +/// +/// \param DeclEnd will receive the source location of the last token +/// within this declaration. +/// +/// \returns the new declaration. +Decl * +Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo, + SourceLocation &DeclEnd) { + assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && + "Template information required"); + assert(Tok.is(tok::kw_concept) && + "ParseConceptDefinition must be called when at a 'concept' keyword"); + + ConsumeToken(); // Consume 'concept' + + SourceLocation BoolKWLoc; + if (TryConsumeToken(tok::kw_bool, BoolKWLoc)) + Diag(Tok.getLocation(), diag::ext_concept_legacy_bool_keyword) << + FixItHint::CreateRemoval(SourceLocation(BoolKWLoc)); + + DiagnoseAndSkipCXX11Attributes(); + + CXXScopeSpec SS; + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*EnteringContext=*/false, /*MayBePseudoDestructor=*/nullptr, + /*IsTypename=*/false, /*LastII=*/nullptr, /*OnlyNamespace=*/true) || + SS.isInvalid()) { + SkipUntil(tok::semi); + return nullptr; + } + + if (SS.isNotEmpty()) + Diag(SS.getBeginLoc(), + diag::err_concept_definition_not_identifier); + + UnqualifiedId Result; + if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, + /*AllowDestructorName=*/false, + /*AllowConstructorName=*/false, + /*AllowDeductionGuide=*/false, + /*ObjectType=*/ParsedType(), /*TemplateKWLoc=*/nullptr, + Result)) { + SkipUntil(tok::semi); + return nullptr; + } + + if (Result.getKind() != UnqualifiedIdKind::IK_Identifier) { + Diag(Result.getBeginLoc(), diag::err_concept_definition_not_identifier); + SkipUntil(tok::semi); + return nullptr; + } + + IdentifierInfo *Id = Result.Identifier; + SourceLocation IdLoc = Result.getBeginLoc(); + + DiagnoseAndSkipCXX11Attributes(); + + if (!TryConsumeToken(tok::equal)) { + Diag(Tok.getLocation(), diag::err_expected) << tok::equal; + SkipUntil(tok::semi); + return nullptr; + } + + ExprResult ConstraintExprResult = + Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression()); + if (ConstraintExprResult.isInvalid()) { + SkipUntil(tok::semi); + return nullptr; + } + + DeclEnd = Tok.getLocation(); + ExpectAndConsumeSemi(diag::err_expected_semi_declaration); + Expr *ConstraintExpr = ConstraintExprResult.get(); + return Actions.ActOnConceptDefinition(getCurScope(), + *TemplateInfo.TemplateParams, + Id, IdLoc, ConstraintExpr); +} + /// ParseTemplateParameters - Parses a template-parameter-list enclosed in /// angle brackets. Depth is the depth of this template-parameter-list, which /// is the number of template headers directly enclosing this template header. @@ -913,7 +1013,7 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, PrevTokLocation = RAngleLoc; } else { PrevTokLocation = TokBeforeGreaterLoc; - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject=*/true); Tok = Greater; } @@ -1025,6 +1125,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // If we failed to parse the template ID but skipped ahead to a >, we're not // going to be able to form a token annotation. Eat the '>' if present. TryConsumeToken(tok::greater); + // FIXME: Annotate the token stream so we don't produce the same errors + // again if we're doing this annotation as part of a tentative parse. return true; } @@ -1033,13 +1135,15 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // Build the annotation token. if (TNK == TNK_Type_template && AllowTypeAnnotation) { TypeResult Type = Actions.ActOnTemplateIdType( - SS, TemplateKWLoc, Template, TemplateName.Identifier, + getCurScope(), SS, TemplateKWLoc, Template, TemplateName.Identifier, TemplateNameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc); if (Type.isInvalid()) { // If we failed to parse the template ID but skipped ahead to a >, we're // not going to be able to form a token annotation. Eat the '>' if // present. TryConsumeToken(tok::greater); + // FIXME: Annotate the token stream so we don't produce the same errors + // again if we're doing this annotation as part of a tentative parse. return true; } @@ -1102,14 +1206,16 @@ void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); assert((TemplateId->Kind == TNK_Type_template || - TemplateId->Kind == TNK_Dependent_template_name) && + TemplateId->Kind == TNK_Dependent_template_name || + TemplateId->Kind == TNK_Undeclared_template) && "Only works for type and dependent templates"); ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult Type - = Actions.ActOnTemplateIdType(TemplateId->SS, + = Actions.ActOnTemplateIdType(getCurScope(), + TemplateId->SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->Name, @@ -1266,36 +1372,6 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { ExprArg.get(), Loc); } -/// Determine whether the current tokens can only be parsed as a -/// template argument list (starting with the '<') and never as a '<' -/// expression. -bool Parser::IsTemplateArgumentList(unsigned Skip) { - struct AlwaysRevertAction : TentativeParsingAction { - AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { } - ~AlwaysRevertAction() { Revert(); } - } Tentative(*this); - - while (Skip) { - ConsumeAnyToken(); - --Skip; - } - - // '<' - if (!TryConsumeToken(tok::less)) - return false; - - // An empty template argument list. - if (Tok.is(tok::greater)) - return true; - - // See whether we have declaration specifiers, which indicate a type. - while (isCXXDeclarationSpecifier() == TPResult::True) - ConsumeAnyToken(); - - // If we have a '>' or a ',' then this is a template argument list. - return Tok.isOneOf(tok::greater, tok::comma); -} - /// ParseTemplateArgumentList - Parse a C++ template-argument-list /// (C++ [temp.names]). Returns true if there was an error. /// @@ -1420,7 +1496,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { // Append the current token at the end of the new token stream so that it // doesn't get lost. LPT.Toks.push_back(Tok); - PP.EnterTokenStream(LPT.Toks, true); + PP.EnterTokenStream(LPT.Toks, true, /*IsReinject*/true); // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index de39e0675fdb8..a413f9a94148a 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -1,9 +1,8 @@ //===--- ParseTentative.cpp - Ambiguity Resolution Parsing ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -591,9 +590,11 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { } else if (Context == TypeIdAsTemplateArgument && (Tok.isOneOf(tok::greater, tok::comma) || (getLangOpts().CPlusPlus11 && - (Tok.is(tok::greatergreater) || + (Tok.isOneOf(tok::greatergreater, + tok::greatergreatergreater) || (Tok.is(tok::ellipsis) && NextToken().isOneOf(tok::greater, tok::greatergreater, + tok::greatergreatergreater, tok::comma)))))) { TPR = TPResult::True; isAmbiguous = true; @@ -652,12 +653,15 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, if (!Disambiguate && !getLangOpts().ObjC) return CAK_AttributeSpecifier; + // '[[using ns: ...]]' is an attribute. + if (GetLookAheadToken(2).is(tok::kw_using)) + return CAK_AttributeSpecifier; + RevertingTentativeParsingAction PA(*this); // Opening brackets were checked for above. ConsumeBracket(); - // Outside Obj-C++11, treat anything with a matching ']]' as an attribute. if (!getLangOpts().ObjC) { ConsumeBracket(); @@ -676,24 +680,45 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, // 4) [[obj]{ return self; }() doStuff]; Lambda in message send. // (1) is an attribute, (2) is ill-formed, and (3) and (4) are accepted. - // If we have a lambda-introducer, then this is definitely not a message send. + // Check to see if this is a lambda-expression. // FIXME: If this disambiguation is too slow, fold the tentative lambda parse // into the tentative attribute parse below. - LambdaIntroducer Intro; - if (!TryParseLambdaIntroducer(Intro)) { - // A lambda cannot end with ']]', and an attribute must. - bool IsAttribute = Tok.is(tok::r_square); - - if (IsAttribute) - // Case 1: C++11 attribute. - return CAK_AttributeSpecifier; + { + RevertingTentativeParsingAction LambdaTPA(*this); + LambdaIntroducer Intro; + LambdaIntroducerTentativeParse Tentative; + if (ParseLambdaIntroducer(Intro, &Tentative)) { + // We hit a hard error after deciding this was not an attribute. + // FIXME: Don't parse and annotate expressions when disambiguating + // against an attribute. + return CAK_NotAttributeSpecifier; + } - if (OuterMightBeMessageSend) - // Case 4: Lambda in message send. + switch (Tentative) { + case LambdaIntroducerTentativeParse::MessageSend: + // Case 3: The inner construct is definitely a message send, so the + // outer construct is definitely not an attribute. return CAK_NotAttributeSpecifier; - // Case 2: Lambda in array size / index. - return CAK_InvalidAttributeSpecifier; + case LambdaIntroducerTentativeParse::Success: + case LambdaIntroducerTentativeParse::Incomplete: + // This is a lambda-introducer or attribute-specifier. + if (Tok.is(tok::r_square)) + // Case 1: C++11 attribute. + return CAK_AttributeSpecifier; + + if (OuterMightBeMessageSend) + // Case 4: Lambda in message send. + return CAK_NotAttributeSpecifier; + + // Case 2: Lambda in array size / index. + return CAK_InvalidAttributeSpecifier; + + case LambdaIntroducerTentativeParse::Invalid: + // No idea what this is; we couldn't parse it as a lambda-introducer. + // Might still be an attribute-specifier or a message send. + break; + } } ConsumeBracket(); @@ -1148,7 +1173,7 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) { } namespace { -class TentativeParseCCC : public CorrectionCandidateCallback { +class TentativeParseCCC final : public CorrectionCandidateCallback { public: TentativeParseCCC(const Token &Next) { WantRemainingKeywords = false; @@ -1166,6 +1191,10 @@ public: return CorrectionCandidateCallback::ValidateCandidate(Candidate); } + + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<TentativeParseCCC>(*this); + } }; } /// isCXXDeclarationSpecifier - Returns TPResult::True if it is a declaration @@ -1173,12 +1202,17 @@ public: /// be either a decl-specifier or a function-style cast, and TPResult::Error /// if a parsing error was found and reported. /// -/// If HasMissingTypename is provided, a name with a dependent scope specifier -/// will be treated as ambiguous if the 'typename' keyword is missing. If this -/// happens, *HasMissingTypename will be set to 'true'. This will also be used -/// as an indicator that undeclared identifiers (which will trigger a later -/// parse error) should be treated as types. Returns TPResult::Ambiguous in -/// such cases. +/// If InvalidAsDeclSpec is not null, some cases that would be ill-formed as +/// declaration specifiers but possibly valid as some other kind of construct +/// return TPResult::Ambiguous instead of TPResult::False. When this happens, +/// the intent is to keep trying to disambiguate, on the basis that we might +/// find a better reason to treat this construct as a declaration later on. +/// When this happens and the name could possibly be valid in some other +/// syntactic context, *InvalidAsDeclSpec is set to 'true'. The current cases +/// that trigger this are: +/// +/// * When parsing X::Y (with no 'typename') where X is dependent +/// * When parsing X<Y> where X is undeclared /// /// decl-specifier: /// storage-class-specifier @@ -1187,6 +1221,7 @@ public: /// 'friend' /// 'typedef' /// [C++11] 'constexpr' +/// [C++20] 'consteval' /// [GNU] attributes declaration-specifiers[opt] /// /// storage-class-specifier: @@ -1276,7 +1311,7 @@ public: /// Parser::TPResult Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, - bool *HasMissingTypename) { + bool *InvalidAsDeclSpec) { switch (Tok.getKind()) { case tok::identifier: { // Check for need to substitute AltiVec __vector keyword @@ -1294,8 +1329,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // a parse error one way or another. In that case, tell the caller that // this is ambiguous. Typo-correct to type and expression keywords and // to types and identifiers, in order to try to recover from errors. - switch (TryAnnotateName(false /* no nested name specifier */, - llvm::make_unique<TentativeParseCCC>(Next))) { + TentativeParseCCC CCC(Next); + switch (TryAnnotateName(false /* no nested name specifier */, &CCC)) { case ANK_Error: return TPResult::Error; case ANK_TentativeDecl: @@ -1316,7 +1351,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // argument is an error, and was probably intended to be a type. return GreaterThanIsOperator ? TPResult::True : TPResult::False; case ANK_Unresolved: - return HasMissingTypename ? TPResult::Ambiguous : TPResult::False; + return InvalidAsDeclSpec ? TPResult::Ambiguous : TPResult::False; case ANK_Success: break; } @@ -1337,7 +1372,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, } // We annotated this token as something. Recurse to handle whatever we got. - return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); + return isCXXDeclarationSpecifier(BracedCastResult, InvalidAsDeclSpec); } case tok::kw_typename: // typename T::type @@ -1345,7 +1380,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return TPResult::Error; - return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); + return isCXXDeclarationSpecifier(BracedCastResult, InvalidAsDeclSpec); case tok::coloncolon: { // ::foo::bar const Token &Next = NextToken(); @@ -1360,7 +1395,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return TPResult::Error; - return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); + return isCXXDeclarationSpecifier(BracedCastResult, InvalidAsDeclSpec); // decl-specifier: // storage-class-specifier @@ -1372,6 +1407,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw_friend: case tok::kw_typedef: case tok::kw_constexpr: + case tok::kw_consteval: // storage-class-specifier case tok::kw_register: case tok::kw_static: @@ -1411,11 +1447,24 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // cv-qualifier case tok::kw_const: case tok::kw_volatile: + return TPResult::True; + + // OpenCL address space qualifiers + case tok::kw_private: + if (!getLangOpts().OpenCL) + return TPResult::False; + LLVM_FALLTHROUGH; case tok::kw___private: case tok::kw___local: case tok::kw___global: case tok::kw___constant: case tok::kw___generic: + // OpenCL access qualifiers + case tok::kw___read_only: + case tok::kw___write_only: + case tok::kw___read_write: + // OpenCL pipe + case tok::kw_pipe: // GNU case tok::kw_restrict: @@ -1455,6 +1504,16 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::annot_template_id: { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + // If lookup for the template-name found nothing, don't assume we have a + // definitive disambiguation result yet. + if (TemplateId->Kind == TNK_Undeclared_template && InvalidAsDeclSpec) { + // 'template-id(' can be a valid expression but not a valid decl spec if + // the template-name is not declared, but we don't consider this to be a + // definitive disambiguation. In any other context, it's an error either + // way. + *InvalidAsDeclSpec = NextToken().is(tok::l_paren); + return TPResult::Ambiguous; + } if (TemplateId->Kind != TNK_Type_template) return TPResult::False; CXXScopeSpec SS; @@ -1483,17 +1542,28 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, TPResult TPR = TPResult::False; if (!isIdentifier) TPR = isCXXDeclarationSpecifier(BracedCastResult, - HasMissingTypename); + InvalidAsDeclSpec); if (isIdentifier || TPR == TPResult::True || TPR == TPResult::Error) return TPResult::Error; - if (HasMissingTypename) { + if (InvalidAsDeclSpec) { // We can't tell whether this is a missing 'typename' or a valid // expression. - *HasMissingTypename = true; + *InvalidAsDeclSpec = true; return TPResult::Ambiguous; + } else { + // In MS mode, if InvalidAsDeclSpec is not provided, and the tokens + // are or the form *) or &) *> or &> &&>, this can't be an expression. + // The typename must be missing. + if (getLangOpts().MSVCCompat) { + if (((Tok.is(tok::amp) || Tok.is(tok::star)) && + (NextToken().is(tok::r_paren) || + NextToken().is(tok::greater))) || + (Tok.is(tok::ampamp) && NextToken().is(tok::greater))) + return TPResult::True; + } } } else { // Try to resolve the name. If it doesn't exist, assume it was @@ -1520,8 +1590,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, ? TPResult::True : TPResult::False; case ANK_Unresolved: - return HasMissingTypename ? TPResult::Ambiguous - : TPResult::False; + return InvalidAsDeclSpec ? TPResult::Ambiguous : TPResult::False; case ANK_Success: break; } @@ -1529,8 +1598,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // Annotated it, check again. assert(Tok.isNot(tok::annot_cxxscope) || NextToken().isNot(tok::identifier)); - return isCXXDeclarationSpecifier(BracedCastResult, - HasMissingTypename); + return isCXXDeclarationSpecifier(BracedCastResult, InvalidAsDeclSpec); } } return TPResult::False; @@ -1601,6 +1669,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw___float128: case tok::kw_void: case tok::annot_decltype: +#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: +#include "clang/Basic/OpenCLImageTypes.def" if (NextToken().is(tok::l_paren)) return TPResult::Ambiguous; @@ -1694,6 +1764,8 @@ bool Parser::isCXXDeclarationSpecifierAType() { case tok::kw_void: case tok::kw___unknown_anytype: case tok::kw___auto_type: +#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: +#include "clang/Basic/OpenCLImageTypes.def" return true; case tok::kw_auto: @@ -1855,31 +1927,31 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration, // decl-specifier-seq '{' is not a parameter in C++11. TPResult TPR = isCXXDeclarationSpecifier(TPResult::False, InvalidAsDeclaration); + // A declaration-specifier (not followed by '(' or '{') means this can't be + // an expression, but it could still be a template argument. + if (TPR != TPResult::Ambiguous && + !(VersusTemplateArgument && TPR == TPResult::True)) + return TPR; - if (VersusTemplateArgument && TPR == TPResult::True) { - // Consume the decl-specifier-seq. We have to look past it, since a - // type-id might appear here in a template argument. - bool SeenType = false; - do { - SeenType |= isCXXDeclarationSpecifierAType(); - if (TryConsumeDeclarationSpecifier() == TPResult::Error) - return TPResult::Error; - - // If we see a parameter name, this can't be a template argument. - if (SeenType && Tok.is(tok::identifier)) - return TPResult::True; - - TPR = isCXXDeclarationSpecifier(TPResult::False, - InvalidAsDeclaration); - if (TPR == TPResult::Error) - return TPR; - } while (TPR != TPResult::False); - } else if (TPR == TPResult::Ambiguous) { - // Disambiguate what follows the decl-specifier. + bool SeenType = false; + do { + SeenType |= isCXXDeclarationSpecifierAType(); if (TryConsumeDeclarationSpecifier() == TPResult::Error) return TPResult::Error; - } else - return TPR; + + // If we see a parameter name, this can't be a template argument. + if (SeenType && Tok.is(tok::identifier)) + return TPResult::True; + + TPR = isCXXDeclarationSpecifier(TPResult::False, + InvalidAsDeclaration); + if (TPR == TPResult::Error) + return TPR; + + // Two declaration-specifiers means this can't be an expression. + if (TPR == TPResult::True && !VersusTemplateArgument) + return TPR; + } while (TPR != TPResult::False); // declarator // abstract-declarator[opt] @@ -1998,3 +2070,54 @@ Parser::TPResult Parser::TryParseBracketDeclarator() { return TPResult::Ambiguous; } + +/// Determine whether we might be looking at the '<' template-argument-list '>' +/// of a template-id or simple-template-id, rather than a less-than comparison. +/// This will often fail and produce an ambiguity, but should never be wrong +/// if it returns True or False. +Parser::TPResult Parser::isTemplateArgumentList(unsigned TokensToSkip) { + if (!TokensToSkip) { + if (Tok.isNot(tok::less)) + return TPResult::False; + if (NextToken().is(tok::greater)) + return TPResult::True; + } + + RevertingTentativeParsingAction PA(*this); + + while (TokensToSkip) { + ConsumeAnyToken(); + --TokensToSkip; + } + + if (!TryConsumeToken(tok::less)) + return TPResult::False; + + // We can't do much to tell an expression apart from a template-argument, + // but one good distinguishing factor is that a "decl-specifier" not + // followed by '(' or '{' can't appear in an expression. + bool InvalidAsTemplateArgumentList = false; + if (isCXXDeclarationSpecifier(TPResult::False, + &InvalidAsTemplateArgumentList) == + TPResult::True) + return TPResult::True; + if (InvalidAsTemplateArgumentList) + return TPResult::False; + + // FIXME: In many contexts, X<thing1, Type> can only be a + // template-argument-list. But that's not true in general: + // + // using b = int; + // void f() { + // int a = A<B, b, c = C>D; // OK, declares b, not a template-id. + // + // X<Y<0, int> // ', int>' might be end of X's template argument list + // + // We might be able to disambiguate a few more cases if we're careful. + + // A template-argument-list must be terminated by a '>'. + if (SkipUntil({tok::greater, tok::greatergreater, tok::greatergreatergreater}, + StopAtSemi | StopBeforeMatch)) + return TPResult::Ambiguous; + return TPResult::False; +} diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index a93db799f8fe2..9124f1558664d 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1,9 +1,8 @@ //===--- Parser.cpp - C Language Family Parser ----------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -316,6 +315,14 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) { else SkipUntil(tok::r_brace); break; + case tok::question: + // Recursively skip ? ... : pairs; these function as brackets. But + // still stop at a semicolon if requested. + ConsumeToken(); + SkipUntil(tok::colon, + SkipUntilFlags(unsigned(Flags) & + unsigned(StopAtCodeCompletion | StopAtSemi))); + break; // Okay, we found a ']' or '}' or ')', which we think should be balanced. // Since the user wasn't looking for this token (if they were, it would @@ -461,6 +468,8 @@ void Parser::Initialize() { Ident_sealed = nullptr; Ident_override = nullptr; Ident_GNU_final = nullptr; + Ident_import = nullptr; + Ident_module = nullptr; Ident_super = &PP.getIdentifierTable().get("super"); @@ -513,6 +522,11 @@ void Parser::Initialize() { PP.SetPoisonReason(Ident_AbnormalTermination,diag::err_seh___finally_block); } + if (getLangOpts().CPlusPlusModules) { + Ident_import = PP.getIdentifierInfo("import"); + Ident_module = PP.getIdentifierInfo("module"); + } + Actions.Initialize(); // Prime the lexer look-ahead. @@ -526,6 +540,16 @@ void Parser::LateTemplateParserCleanupCallback(void *P) { DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(((Parser *)P)->TemplateIds); } +/// Parse the first top-level declaration in a translation unit. +/// +/// translation-unit: +/// [C] external-declaration +/// [C] translation-unit external-declaration +/// [C++] top-level-declaration-seq[opt] +/// [C++20] global-module-fragment[opt] module-declaration +/// top-level-declaration-seq[opt] private-module-fragment[opt] +/// +/// Note that in C, it is an error if there is no first declaration. bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) { Actions.ActOnStartOfTranslationUnit(); @@ -533,7 +557,7 @@ bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) { // 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); + bool NoTopLevelDecls = ParseTopLevelDecl(Result, true); if (NoTopLevelDecls && !Actions.getASTContext().getExternalSource() && !getLangOpts().CPlusPlus) Diag(diag::ext_empty_translation_unit); @@ -543,7 +567,11 @@ bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) { /// 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) { +/// +/// top-level-declaration: +/// declaration +/// [C++20] module-import-declaration +bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) { DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds); // Skip over the EOF token, flagging end of previous input for incremental @@ -558,13 +586,46 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { return false; case tok::kw_export: - if (NextToken().isNot(tok::kw_module)) + switch (NextToken().getKind()) { + case tok::kw_module: + goto module_decl; + + // Note: no need to handle kw_import here. We only form kw_import under + // the Modules TS, and in that case 'export import' is parsed as an + // export-declaration containing an import-declaration. + + // Recognize context-sensitive C++20 'export module' and 'export import' + // declarations. + case tok::identifier: { + IdentifierInfo *II = NextToken().getIdentifierInfo(); + if ((II == Ident_module || II == Ident_import) && + GetLookAheadToken(2).isNot(tok::coloncolon)) { + if (II == Ident_module) + goto module_decl; + else + goto import_decl; + } break; - LLVM_FALLTHROUGH; + } + + default: + break; + } + break; + case tok::kw_module: - Result = ParseModuleDecl(); + module_decl: + Result = ParseModuleDecl(IsFirstDecl); return false; + // tok::kw_import is handled by ParseExternalDeclaration. (Under the Modules + // TS, an import can occur within an export block.) + import_decl: { + Decl *ImportDecl = ParseModuleImport(SourceLocation()); + Result = Actions.ConvertDeclToDeclGroup(ImportDecl); + return false; + } + case tok::annot_module_include: Actions.ActOnModuleInclude(Tok.getLocation(), reinterpret_cast<Module *>( @@ -584,10 +645,6 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { ConsumeAnnotationToken(); return false; - case tok::annot_pragma_attribute: - HandlePragmaAttribute(); - return false; - case tok::eof: // Late template parsing can begin. if (getLangOpts().DelayedTemplateParsing) @@ -600,6 +657,21 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { //else don't tell Sema that we ended parsing: more input might come. return true; + case tok::identifier: + // C++2a [basic.link]p3: + // A token sequence beginning with 'export[opt] module' or + // 'export[opt] import' and not immediately followed by '::' + // is never interpreted as the declaration of a top-level-declaration. + if ((Tok.getIdentifierInfo() == Ident_module || + Tok.getIdentifierInfo() == Ident_import) && + NextToken().isNot(tok::coloncolon)) { + if (Tok.getIdentifierInfo() == Ident_module) + goto module_decl; + else + goto import_decl; + } + break; + default: break; } @@ -699,6 +771,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::annot_pragma_dump: HandlePragmaDump(); return nullptr; + case tok::annot_pragma_attribute: + HandlePragmaAttribute(); + return nullptr; case tok::semi: // Either a C++11 empty-declaration or attribute-declaration. SingleDecl = @@ -770,7 +845,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, SingleDecl = ParseModuleImport(SourceLocation()); break; case tok::kw_export: - if (getLangOpts().ModulesTS) { + if (getLangOpts().CPlusPlusModules || getLangOpts().ModulesTS) { SingleDecl = ParseExportDeclaration(); break; } @@ -914,7 +989,8 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) { /// declaration: [C99 6.7] /// declaration-specifiers init-declarator-list[opt] ';' /// [!C99] init-declarator-list ';' [TODO: warn in c99 mode] -/// [OMP] threadprivate-directive [TODO] +/// [OMP] threadprivate-directive +/// [OMP] allocate-directive [TODO] /// Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, @@ -981,9 +1057,10 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, if (getLangOpts().ObjC && Tok.is(tok::at)) { SourceLocation AtLoc = ConsumeToken(); // the "@" if (!Tok.isObjCAtKeyword(tok::objc_interface) && - !Tok.isObjCAtKeyword(tok::objc_protocol)) { + !Tok.isObjCAtKeyword(tok::objc_protocol) && + !Tok.isObjCAtKeyword(tok::objc_implementation)) { Diag(Tok, diag::err_objc_unexpected_attr); - SkipUntil(tok::semi); // FIXME: better skip? + SkipUntil(tok::semi); return nullptr; } @@ -998,6 +1075,9 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, if (Tok.isObjCAtKeyword(tok::objc_protocol)) return ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes()); + if (Tok.isObjCAtKeyword(tok::objc_implementation)) + return ParseObjCAtImplementationDeclaration(AtLoc, DS.getAttributes()); + return Actions.ConvertDeclToDeclGroup( ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes())); } @@ -1465,7 +1545,7 @@ void Parser::AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation) { if (PP.isBacktrackEnabled()) PP.RevertCachedTokens(1); else - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject=*/true); Tok.setKind(tok::annot_cxxscope); Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS)); Tok.setAnnotationRange(SS.getRange()); @@ -1488,7 +1568,7 @@ void Parser::AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation) { /// no typo correction will be performed. Parser::AnnotatedNameKind Parser::TryAnnotateName(bool IsAddressOfOperand, - std::unique_ptr<CorrectionCandidateCallback> CCC) { + CorrectionCandidateCallback *CCC) { assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope)); const bool EnteringContext = false; @@ -1524,9 +1604,23 @@ Parser::TryAnnotateName(bool IsAddressOfOperand, // after a scope specifier, because in general we can't recover from typos // there (eg, after correcting 'A::template B<X>::C' [sic], we would need to // jump back into scope specifier parsing). - Sema::NameClassification Classification = Actions.ClassifyName( - getCurScope(), SS, Name, NameLoc, Next, IsAddressOfOperand, - SS.isEmpty() ? std::move(CCC) : nullptr); + Sema::NameClassification Classification = + Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next, + IsAddressOfOperand, SS.isEmpty() ? CCC : nullptr); + + // If name lookup found nothing and we guessed that this was a template name, + // double-check before committing to that interpretation. C++20 requires that + // we interpret this as a template-id if it can be, but if it can't be, then + // this is an error recovery case. + if (Classification.getKind() == Sema::NC_UndeclaredTemplate && + isTemplateArgumentList(1) == TPResult::False) { + // It's not a template-id; re-classify without the '<' as a hint. + Token FakeNext = Next; + FakeNext.setKind(tok::unknown); + Classification = + Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, FakeNext, + IsAddressOfOperand, SS.isEmpty() ? CCC : nullptr); + } switch (Classification.getKind()) { case Sema::NC_Error: @@ -1596,7 +1690,8 @@ Parser::TryAnnotateName(bool IsAddressOfOperand, } LLVM_FALLTHROUGH; case Sema::NC_VarTemplate: - case Sema::NC_FunctionTemplate: { + case Sema::NC_FunctionTemplate: + case Sema::NC_UndeclaredTemplate: { // We have a type, variable or function template followed by '<'. ConsumeToken(); UnqualifiedId Id; @@ -1669,7 +1764,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() { Token TypedefToken; PP.Lex(TypedefToken); bool Result = TryAnnotateTypeOrScopeToken(); - PP.EnterToken(Tok); + PP.EnterToken(Tok, /*IsReinject=*/true); Tok = TypedefToken; if (!Result) Diag(Tok.getLocation(), diag::warn_expected_qualified_after_typename); @@ -1719,7 +1814,8 @@ bool Parser::TryAnnotateTypeOrScopeToken() { } else if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind != TNK_Type_template && - TemplateId->Kind != TNK_Dependent_template_name) { + TemplateId->Kind != TNK_Dependent_template_name && + TemplateId->Kind != TNK_Undeclared_template) { Diag(Tok, diag::err_typename_refers_to_non_type_template) << Tok.getAnnotationRange(); return true; @@ -1818,6 +1914,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, } // If this is a template-id, annotate with a template-id or type token. + // FIXME: This appears to be dead code. We already have formed template-id + // tokens when parsing the scope specifier; this can never form a new one. if (NextToken().is(tok::less)) { TemplateTy Template; UnqualifiedId TemplateName; @@ -1828,14 +1926,19 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, /*hasTemplateKeyword=*/false, TemplateName, /*ObjectType=*/nullptr, /*EnteringContext*/false, Template, MemberOfUnknownSpecialization)) { - // Consume the identifier. - ConsumeToken(); - if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), - TemplateName)) { - // If an unrecoverable error occurred, we need to return true here, - // because the token stream is in a damaged state. We may not return - // a valid identifier. - return true; + // Only annotate an undeclared template name as a template-id if the + // following tokens have the form of a template argument list. + if (TNK != TNK_Undeclared_template || + isTemplateArgumentList(1) != TPResult::False) { + // Consume the identifier. + ConsumeToken(); + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName)) { + // If an unrecoverable error occurred, we need to return true here, + // because the token stream is in a damaged state. We may not + // return a valid identifier. + return true; + } } } } @@ -2071,38 +2174,82 @@ 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. +/// Parse a declaration beginning with the 'module' keyword or C++20 +/// context-sensitive keyword (optionally preceded by 'export'). /// -/// module-declaration: [Modules TS + P0273R0 + P0629R0] -/// 'export'[opt] 'module' 'partition'[opt] -/// module-name attribute-specifier-seq[opt] ';' +/// module-declaration: [Modules TS + P0629R0] +/// 'export'[opt] 'module' module-name attribute-specifier-seq[opt] ';' /// -/// Note that 'partition' is a context-sensitive keyword. -Parser::DeclGroupPtrTy Parser::ParseModuleDecl() { +/// global-module-fragment: [C++2a] +/// 'module' ';' top-level-declaration-seq[opt] +/// module-declaration: [C++2a] +/// 'export'[opt] 'module' module-name module-partition[opt] +/// attribute-specifier-seq[opt] ';' +/// private-module-fragment: [C++2a] +/// 'module' ':' 'private' ';' top-level-declaration-seq[opt] +Parser::DeclGroupPtrTy Parser::ParseModuleDecl(bool IsFirstDecl) { SourceLocation StartLoc = Tok.getLocation(); Sema::ModuleDeclKind MDK = TryConsumeToken(tok::kw_export) ? Sema::ModuleDeclKind::Interface : Sema::ModuleDeclKind::Implementation; - assert(Tok.is(tok::kw_module) && "not a module declaration"); + assert( + (Tok.is(tok::kw_module) || + (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_module)) && + "not a module declaration"); SourceLocation ModuleLoc = ConsumeToken(); - if (Tok.is(tok::identifier) && NextToken().is(tok::identifier) && - Tok.getIdentifierInfo()->isStr("partition")) { - // If 'partition' is present, this must be a module interface unit. - if (MDK != Sema::ModuleDeclKind::Interface) - Diag(Tok.getLocation(), diag::err_module_implementation_partition) - << FixItHint::CreateInsertion(ModuleLoc, "export "); - MDK = Sema::ModuleDeclKind::Partition; + // Attributes appear after the module name, not before. + // FIXME: Suggest moving the attributes later with a fixit. + DiagnoseAndSkipCXX11Attributes(); + + // Parse a global-module-fragment, if present. + if (getLangOpts().CPlusPlusModules && Tok.is(tok::semi)) { + SourceLocation SemiLoc = ConsumeToken(); + if (!IsFirstDecl) { + Diag(StartLoc, diag::err_global_module_introducer_not_at_start) + << SourceRange(StartLoc, SemiLoc); + return nullptr; + } + if (MDK == Sema::ModuleDeclKind::Interface) { + Diag(StartLoc, diag::err_module_fragment_exported) + << /*global*/0 << FixItHint::CreateRemoval(StartLoc); + } + return Actions.ActOnGlobalModuleFragmentDecl(ModuleLoc); + } + + // Parse a private-module-fragment, if present. + if (getLangOpts().CPlusPlusModules && Tok.is(tok::colon) && + NextToken().is(tok::kw_private)) { + if (MDK == Sema::ModuleDeclKind::Interface) { + Diag(StartLoc, diag::err_module_fragment_exported) + << /*private*/1 << FixItHint::CreateRemoval(StartLoc); + } ConsumeToken(); + SourceLocation PrivateLoc = ConsumeToken(); + DiagnoseAndSkipCXX11Attributes(); + ExpectAndConsumeSemi(diag::err_private_module_fragment_expected_semi); + return Actions.ActOnPrivateModuleFragmentDecl(ModuleLoc, PrivateLoc); } SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; if (ParseModuleName(ModuleLoc, Path, /*IsImport*/false)) return nullptr; + // Parse the optional module-partition. + if (Tok.is(tok::colon)) { + SourceLocation ColonLoc = ConsumeToken(); + SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Partition; + if (ParseModuleName(ModuleLoc, Partition, /*IsImport*/false)) + return nullptr; + + // FIXME: Support module partition declarations. + Diag(ColonLoc, diag::err_unsupported_module_partition) + << SourceRange(ColonLoc, Partition.back().second); + // Recover by parsing as a non-partition. + } + // We don't support any module attributes yet; just parse them and diagnose. ParsedAttributesWithRange Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); @@ -2110,7 +2257,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl() { ExpectAndConsumeSemi(diag::err_module_expected_semi); - return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path); + return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path, IsFirstDecl); } /// Parse a module import declaration. This is essentially the same for @@ -2121,17 +2268,50 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl() { /// '@' 'import' module-name ';' /// [ModTS] module-import-declaration: /// 'import' module-name attribute-specifier-seq[opt] ';' +/// [C++2a] module-import-declaration: +/// 'export'[opt] 'import' module-name +/// attribute-specifier-seq[opt] ';' +/// 'export'[opt] 'import' module-partition +/// attribute-specifier-seq[opt] ';' +/// 'export'[opt] 'import' header-name +/// attribute-specifier-seq[opt] ';' Decl *Parser::ParseModuleImport(SourceLocation AtLoc) { - assert((AtLoc.isInvalid() ? Tok.is(tok::kw_import) + SourceLocation StartLoc = AtLoc.isInvalid() ? Tok.getLocation() : AtLoc; + + SourceLocation ExportLoc; + TryConsumeToken(tok::kw_export, ExportLoc); + + assert((AtLoc.isInvalid() ? Tok.isOneOf(tok::kw_import, tok::identifier) : Tok.isObjCAtKeyword(tok::objc_import)) && "Improper start to module import"); bool IsObjCAtImport = Tok.isObjCAtKeyword(tok::objc_import); SourceLocation ImportLoc = ConsumeToken(); - SourceLocation StartLoc = AtLoc.isInvalid() ? ImportLoc : AtLoc; SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; - if (ParseModuleName(ImportLoc, Path, /*IsImport*/true)) + Module *HeaderUnit = nullptr; + + if (Tok.is(tok::header_name)) { + // This is a header import that the preprocessor decided we should skip + // because it was malformed in some way. Parse and ignore it; it's already + // been diagnosed. + ConsumeToken(); + } else if (Tok.is(tok::annot_header_unit)) { + // This is a header import that the preprocessor mapped to a module import. + HeaderUnit = reinterpret_cast<Module *>(Tok.getAnnotationValue()); + ConsumeAnnotationToken(); + } else if (getLangOpts().CPlusPlusModules && Tok.is(tok::colon)) { + SourceLocation ColonLoc = ConsumeToken(); + if (ParseModuleName(ImportLoc, Path, /*IsImport*/true)) + return nullptr; + + // FIXME: Support module partition import. + Diag(ColonLoc, diag::err_unsupported_module_partition) + << SourceRange(ColonLoc, Path.back().second); return nullptr; + } else { + if (ParseModuleName(ImportLoc, Path, /*IsImport*/true)) + return nullptr; + } ParsedAttributesWithRange Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); @@ -2144,7 +2324,12 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc) { return nullptr; } - DeclResult Import = Actions.ActOnModuleImport(StartLoc, ImportLoc, Path); + DeclResult Import; + if (HeaderUnit) + Import = + Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, HeaderUnit); + else if (!Path.empty()) + Import = Actions.ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Path); ExpectAndConsumeSemi(diag::err_module_expected_semi); if (Import.isInvalid()) return nullptr; |