diff options
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/ParseAST.cpp | 9 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 9 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 101 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 64 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 126 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 123 | ||||
-rw-r--r-- | lib/Parse/ParseInit.cpp | 7 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 47 | ||||
-rw-r--r-- | lib/Parse/ParseOpenMP.cpp | 521 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.cpp | 16 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 139 | ||||
-rw-r--r-- | lib/Parse/ParseStmtAsm.cpp | 9 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 14 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 43 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 236 |
15 files changed, 1101 insertions, 363 deletions
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp index f7703b1bfd..3efd893e49 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 fde3ce00f8..5598058932 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 // //===----------------------------------------------------------------------===// // @@ -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. diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 298a2bad56..c4f02b9b99 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 // //===----------------------------------------------------------------------===// // @@ -223,6 +222,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 +295,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 +328,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)) { @@ -1716,7 +1734,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 +2294,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 +2333,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(), @@ -2627,6 +2649,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; @@ -2832,7 +2857,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(); @@ -3790,19 +3815,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 +3827,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; @@ -3876,6 +3893,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 @@ -4782,9 +4802,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; @@ -4976,6 +4998,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { #include "clang/Basic/OpenCLImageTypes.def" return true; + + case tok::kw_private: + return getLangOpts().OpenCL; } } @@ -5176,6 +5201,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: @@ -6159,6 +6188,20 @@ void Parser::ParseFunctionDeclarator(Declarator &D, Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers()); if (D.getDeclSpec().isConstexprSpecified() && !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 f8359f1e87..c4fe23c60c 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. @@ -1248,9 +1256,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 ++() {...} @@ -2539,6 +2549,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 +3065,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 +3132,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"); @@ -3482,20 +3510,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; } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 4bcbebcbb4..b8f3288284 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! @@ -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; @@ -764,6 +764,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 +1045,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()) { @@ -1115,6 +1118,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 +1142,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 +1157,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()); @@ -1424,7 +1432,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 +1468,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 +1508,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 +1560,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 +1582,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 +1596,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 +1660,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 +1729,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(); @@ -1773,7 +1777,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(); @@ -2327,14 +2332,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 +2422,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 +2554,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 +2849,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)) { diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 3caec6b4de..fbafb43688 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 // //===----------------------------------------------------------------------===// // @@ -564,7 +563,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 +638,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] ']' @@ -1122,6 +1123,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 +1166,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; @@ -1299,6 +1334,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( StmtResult Stmt(ParseCompoundStatementBody()); BodyScope.Exit(); + TemplateParamScope.Exit(); if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid()) return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope()); @@ -1673,23 +1709,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 +1779,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 +1899,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 +2036,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)); @@ -2836,23 +2884,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 +2929,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 +2943,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(); diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 7742a5087c..1444671a31 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index bd55f71793..274ea879e6 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; } @@ -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: @@ -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) { diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index dd2a8aae9f..34798ea39c 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. @@ -704,10 +841,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 +875,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 +892,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 +953,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 +995,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 +1152,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 +1188,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 +1208,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 +1232,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,6 +1302,18 @@ 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; @@ -1051,7 +1330,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 +1434,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 +1562,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 +1591,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 +1612,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 +1708,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 +1781,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 +2075,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 +2155,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 +2175,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 +2191,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 +2205,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 +2264,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 +2277,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 +2391,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 +2425,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 +2455,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 380eb64997..a0458fdbb7 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 // //===----------------------------------------------------------------------===// // @@ -693,13 +692,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 +707,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; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 2974e6a245..cee160565f 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,18 @@ 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; +StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) { + bool IsStmtExprResult = false; + if ((StmtCtx & ParsedStmtContext::InStmtExpr) != ParsedStmtContext()) { + // Look ahead 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); + IsStmtExprResult = Tok.is(tok::r_brace) && NextToken().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 +1038,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 +1054,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 +1087,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 +1991,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 +2022,7 @@ StmtResult Parser::ParseReturnStatement() { } StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, - AllowedConstructsKind Allowed, + ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) { // Create temporary attribute list. @@ -2022,7 +2045,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 +2264,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 +2351,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 9b96c5150e..3c4bc07321 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 // //===----------------------------------------------------------------------===// // @@ -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. diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index e0a7cc6e85..d028c8f4c3 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 @@ -232,6 +232,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); diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index de39e0675f..46366ff43c 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 // //===----------------------------------------------------------------------===// // @@ -1148,7 +1147,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 +1165,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 @@ -1294,8 +1297,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: @@ -1411,11 +1414,22 @@ 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: // GNU case tok::kw_restrict: @@ -1494,6 +1508,17 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // expression. *HasMissingTypename = true; return TPResult::Ambiguous; + } else { + // In MS mode, if HasMissingTypename 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 @@ -1601,6 +1626,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 +1721,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: diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index a93db799f8..6b25d6c038 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 // //===----------------------------------------------------------------------===// // @@ -461,6 +460,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 +514,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 +532,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 +549,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 +559,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,12 +578,45 @@ 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(), @@ -584,10 +637,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 +649,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 +763,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 +837,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 +981,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 +1049,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 +1067,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())); } @@ -1488,7 +1560,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 +1596,9 @@ 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); switch (Classification.getKind()) { case Sema::NC_Error: @@ -2071,38 +2143,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 +2226,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 +2237,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 +2293,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; |