diff options
Diffstat (limited to 'clang/lib/Parse')
-rw-r--r-- | clang/lib/Parse/ParseCXXInlineMethods.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 180 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 428 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 51 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 328 | ||||
-rw-r--r-- | clang/lib/Parse/ParseInit.cpp | 28 | ||||
-rw-r--r-- | clang/lib/Parse/ParseObjc.cpp | 94 | ||||
-rw-r--r-- | clang/lib/Parse/ParseOpenMP.cpp | 425 | ||||
-rw-r--r-- | clang/lib/Parse/ParsePragma.cpp | 30 | ||||
-rw-r--r-- | clang/lib/Parse/ParseStmt.cpp | 80 | ||||
-rw-r--r-- | clang/lib/Parse/ParseStmtAsm.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Parse/ParseTentative.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Parse/Parser.cpp | 37 |
13 files changed, 1133 insertions, 568 deletions
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index b0335905b6f8..116724a0d50b 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -778,6 +778,7 @@ void Parser::ParseLexedPragma(LateParsedPragma &LP) { ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); assert(Tok.isAnnotation() && "Expected annotation token."); switch (Tok.getKind()) { + case tok::annot_attr_openmp: case tok::annot_pragma_openmp: { AccessSpecifier AS = LP.getAccessSpecifier(); ParsedAttributesWithRange Attrs(AttrFactory); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 571164139630..f4f5f461e3b6 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -103,6 +103,24 @@ static bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc, return AttrStartIsInMacro && AttrEndIsInMacro; } +void Parser::ParseAttributes(unsigned WhichAttrKinds, + ParsedAttributesWithRange &Attrs, + SourceLocation *End, + LateParsedAttrList *LateAttrs) { + bool MoreToParse; + do { + // Assume there's nothing left to parse, but if any attributes are in fact + // parsed, loop to ensure all specified attribute combinations are parsed. + MoreToParse = false; + if (WhichAttrKinds & PAKM_CXX11) + MoreToParse |= MaybeParseCXX11Attributes(Attrs, End); + if (WhichAttrKinds & PAKM_GNU) + MoreToParse |= MaybeParseGNUAttributes(Attrs, End, LateAttrs); + if (WhichAttrKinds & PAKM_Declspec) + MoreToParse |= MaybeParseMicrosoftDeclSpecs(Attrs, End); + } while (MoreToParse); +} + /// ParseGNUAttributes - Parse a non-empty attributes list. /// /// [GNU] attributes: @@ -144,15 +162,19 @@ static bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc, /// ',' or ')' are ignored, otherwise they produce a parse error. /// /// We follow the C++ model, but don't allow junk after the identifier. -void Parser::ParseGNUAttributes(ParsedAttributes &attrs, - SourceLocation *endLoc, - LateParsedAttrList *LateAttrs, - Declarator *D) { +void Parser::ParseGNUAttributes(ParsedAttributesWithRange &Attrs, + SourceLocation *EndLoc, + LateParsedAttrList *LateAttrs, Declarator *D) { assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); + SourceLocation StartLoc = Tok.getLocation(), Loc; + + if (!EndLoc) + EndLoc = &Loc; + while (Tok.is(tok::kw___attribute)) { SourceLocation AttrTokLoc = ConsumeToken(); - unsigned OldNumAttrs = attrs.size(); + unsigned OldNumAttrs = Attrs.size(); unsigned OldNumLateAttrs = LateAttrs ? LateAttrs->size() : 0; if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, @@ -180,14 +202,14 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, SourceLocation AttrNameLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) { - attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, ParsedAttr::AS_GNU); continue; } // Handle "parameterized" attributes if (!LateAttrs || !isAttributeLateParsed(*AttrName)) { - ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc, nullptr, + ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, nullptr, SourceLocation(), ParsedAttr::AS_GNU, D); continue; } @@ -220,8 +242,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, SourceLocation Loc = Tok.getLocation(); if (ExpectAndConsume(tok::r_paren)) SkipUntil(tok::r_paren, StopAtSemi); - if (endLoc) - *endLoc = Loc; + if (EndLoc) + *EndLoc = Loc; // If this was declared in a macro, attach the macro IdentifierInfo to the // parsed attribute. @@ -233,8 +255,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, Lexer::getSourceText(ExpansionRange, SM, PP.getLangOpts()); IdentifierInfo *MacroII = PP.getIdentifierInfo(FoundName); - for (unsigned i = OldNumAttrs; i < attrs.size(); ++i) - attrs[i].setMacroIdentifier(MacroII, ExpansionRange.getBegin()); + for (unsigned i = OldNumAttrs; i < Attrs.size(); ++i) + Attrs[i].setMacroIdentifier(MacroII, ExpansionRange.getBegin()); if (LateAttrs) { for (unsigned i = OldNumLateAttrs; i < LateAttrs->size(); ++i) @@ -242,6 +264,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, } } } + + Attrs.Range = SourceRange(StartLoc, *EndLoc); } /// Determine whether the given attribute has an identifier argument. @@ -1589,7 +1613,30 @@ void Parser::DiagnoseProhibitedAttributes( } void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs, - unsigned DiagID) { + unsigned DiagID, bool DiagnoseEmptyAttrs) { + + if (DiagnoseEmptyAttrs && Attrs.empty() && Attrs.Range.isValid()) { + // An attribute list has been parsed, but it was empty. + // This is the case for [[]]. + const auto &LangOpts = getLangOpts(); + auto &SM = PP.getSourceManager(); + Token FirstLSquare; + Lexer::getRawToken(Attrs.Range.getBegin(), FirstLSquare, SM, LangOpts); + + if (FirstLSquare.is(tok::l_square)) { + llvm::Optional<Token> SecondLSquare = + Lexer::findNextToken(FirstLSquare.getLocation(), SM, LangOpts); + + if (SecondLSquare && SecondLSquare->is(tok::l_square)) { + // The attribute range starts with [[, but is empty. So this must + // be [[]], which we are supposed to diagnose because + // DiagnoseEmptyAttrs is true. + Diag(Attrs.Range.getBegin(), DiagID) << Attrs.Range; + return; + } + } + } + for (const ParsedAttr &AL : Attrs) { if (!AL.isCXX11Attribute() && !AL.isC2xAttribute()) continue; @@ -1603,6 +1650,13 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs, } } +void Parser::DiagnoseCXX11AttributeExtension(ParsedAttributesWithRange &Attrs) { + for (const ParsedAttr &PA : Attrs) { + if (PA.isCXX11Attribute() || PA.isC2xAttribute()) + Diag(PA.getLoc(), diag::ext_cxx11_attr_placement) << PA << PA.getRange(); + } +} + // Usually, `__attribute__((attrib)) class Foo {} var` means that attribute // applies to var, not the type Foo. // As an exception to the rule, __declspec(align(...)) before the @@ -1952,8 +2006,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // Check to see if we have a function *definition* which must have a body. if (D.isFunctionDeclarator()) { if (Tok.is(tok::equal) && NextToken().is(tok::code_completion)) { - Actions.CodeCompleteAfterFunctionEquals(D); cutOffParsing(); + Actions.CodeCompleteAfterFunctionEquals(D); return nullptr; } // Look at the next token to make sure that this isn't a function @@ -2292,9 +2346,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( InitializerScopeRAII InitScope(*this, D, ThisDecl); if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteInitializer(getCurScope(), ThisDecl); Actions.FinalizeDeclaration(ThisDecl); - cutOffParsing(); return nullptr; } @@ -3024,6 +3078,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, SourceLocation Loc = Tok.getLocation(); + // Helper for image types in OpenCL. + auto handleOpenCLImageKW = [&] (StringRef Ext, TypeSpecifierType ImageTypeSpec) { + // Check if the image type is supported and otherwise turn the keyword into an identifier + // because image types from extensions are not reserved identifiers. + if (!StringRef(Ext).empty() && !getActions().getOpenCLOptions().isSupported(Ext, getLangOpts())) { + Tok.getIdentifierInfo()->revertTokenIDToIdentifier(); + Tok.setKind(tok::identifier); + return false; + } + isInvalid = DS.SetTypeSpecType(ImageTypeSpec, Loc, PrevSpec, DiagID, Policy); + return true; + }; + switch (Tok.getKind()) { default: DoneWithDeclSpec: @@ -3072,10 +3139,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, = DSContext == DeclSpecContext::DSC_top_level || (DSContext == DeclSpecContext::DSC_class && DS.isFriendSpecified()); + cutOffParsing(); Actions.CodeCompleteDeclSpec(getCurScope(), DS, AllowNonIdentifiers, AllowNestedNameSpecifiers); - return cutOffParsing(); + return; } if (getCurScope()->getFnParent() || getCurScope()->getBlockParent()) @@ -3088,8 +3156,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, else if (CurParsedObjCImpl) CCC = Sema::PCC_ObjCImplementation; + cutOffParsing(); Actions.CodeCompleteOrdinaryName(getCurScope(), CCC); - return cutOffParsing(); + return; } case tok::coloncolon: // ::foo::bar @@ -3485,14 +3554,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; } - // GNU attributes support. + // Attributes support. case tok::kw___attribute: - ParseGNUAttributes(DS.getAttributes(), nullptr, LateAttrs); - continue; - - // Microsoft declspec support. case tok::kw___declspec: - ParseMicrosoftDeclSpecs(DS.getAttributes()); + ParseAttributes(PAKM_GNU | PAKM_Declspec, DS.getAttributes(), nullptr, + LateAttrs); continue; // Microsoft single token adornments. @@ -3631,8 +3697,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // C++ for OpenCL does not allow virtual function qualifier, to avoid // function pointers restricted in OpenCL v2.0 s6.9.a. if (getLangOpts().OpenCLCPlusPlus && - !getActions().getOpenCLOptions().isEnabled( - "__cl_clang_function_pointers")) { + !getActions().getOpenCLOptions().isAvailableOption( + "__cl_clang_function_pointers", getLangOpts())) { DiagID = diag::err_openclcxx_virtual_function; PrevSpec = Tok.getIdentifierInfo()->getNameStart(); isInvalid = true; @@ -3881,18 +3947,22 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw_pipe: if (!getLangOpts().OpenCL || (getLangOpts().OpenCLVersion < 200 && !getLangOpts().OpenCLCPlusPlus)) { - // OpenCL 2.0 defined this keyword. OpenCL 1.2 and earlier should - // support the "pipe" word as identifier. + // OpenCL 2.0 and later define this keyword. OpenCL 1.2 and earlier + // should support the "pipe" word as identifier. Tok.getIdentifierInfo()->revertTokenIDToIdentifier(); + Tok.setKind(tok::identifier); goto DoneWithDeclSpec; } isInvalid = DS.SetTypePipe(true, Loc, PrevSpec, DiagID, Policy); break; -#define GENERIC_IMAGE_TYPE(ImgType, Id) \ - case tok::kw_##ImgType##_t: \ - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_##ImgType##_t, Loc, PrevSpec, \ - DiagID, Policy); \ - break; +// We only need to enumerate each image type once. +#define IMAGE_READ_WRITE_TYPE(Type, Id, Ext) +#define IMAGE_WRITE_TYPE(Type, Id, Ext) +#define IMAGE_READ_TYPE(ImgType, Id, Ext) \ + case tok::kw_##ImgType##_t: \ + if (!handleOpenCLImageKW(Ext, DeclSpec::TST_##ImgType##_t)) \ + goto DoneWithDeclSpec; \ + break; #include "clang/Basic/OpenCLImageTypes.def" case tok::kw___unknown_anytype: isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc, @@ -4002,8 +4072,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___generic: // generic address space is introduced only in OpenCL v2.0 // see OpenCL C Spec v2.0 s6.5.5 - if (Actions.getLangOpts().OpenCLVersion < 200 && - !Actions.getLangOpts().OpenCLCPlusPlus) { + // OpenCL v3.0 introduces __opencl_c_generic_address_space + // feature macro to indicate if generic address space is supported + if (!Actions.getLangOpts().OpenCLGenericAddressSpace) { DiagID = diag::err_opencl_unknown_type_specifier; PrevSpec = Tok.getIdentifierInfo()->getNameStart(); isInvalid = true; @@ -4216,7 +4287,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, } // Parse _Static_assert declaration. - if (Tok.is(tok::kw__Static_assert)) { + if (Tok.isOneOf(tok::kw__Static_assert, tok::kw_static_assert)) { SourceLocation DeclEnd; ParseStaticAssertDeclaration(DeclEnd); continue; @@ -4232,7 +4303,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, continue; } - if (Tok.is(tok::annot_pragma_openmp)) { + if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp)) { // Result can be ignored, because it must be always empty. AccessSpecifier AS = AS_none; ParsedAttributesWithRange Attrs(AttrFactory); @@ -4348,15 +4419,14 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // Parse the tag portion of this. if (Tok.is(tok::code_completion)) { // Code completion for an enum name. + cutOffParsing(); Actions.CodeCompleteTag(getCurScope(), DeclSpec::TST_enum); - return cutOffParsing(); + return; } // If attributes exist after tag, parse them. ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseGNUAttributes(attrs); - MaybeParseCXX11Attributes(attrs); - MaybeParseMicrosoftDeclSpecs(attrs); + MaybeParseAttributes(PAKM_GNU | PAKM_Declspec | PAKM_CXX11, attrs); SourceLocation ScopedEnumKWLoc; bool IsScopedUsingClassTag = false; @@ -4373,9 +4443,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, ProhibitAttributes(attrs); // They are allowed afterwards, though. - MaybeParseGNUAttributes(attrs); - MaybeParseCXX11Attributes(attrs); - MaybeParseMicrosoftDeclSpecs(attrs); + MaybeParseAttributes(PAKM_GNU | PAKM_Declspec | PAKM_CXX11, attrs); } // C++11 [temp.explicit]p12: @@ -4617,7 +4685,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // or opaque-enum-declaration anywhere. if (IsElaboratedTypeSpecifier && !getLangOpts().MicrosoftExt && !getLangOpts().ObjC) { - ProhibitAttributes(attrs); + ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, + /*DiagnoseEmptyAttrs=*/true); if (BaseType.isUsable()) Diag(BaseRange.getBegin(), diag::ext_enum_base_in_type_specifier) << (AllowEnumSpecifier == AllowDefiningTypeSpec::Yes) << BaseRange; @@ -4761,7 +4830,6 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { // If attributes exist after the enumerator, parse them. ParsedAttributesWithRange attrs(AttrFactory); MaybeParseGNUAttributes(attrs); - ProhibitAttributes(attrs); // GNU-style attributes are prohibited. if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) { if (getLangOpts().CPlusPlus) Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 @@ -5059,8 +5127,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { default: return false; case tok::kw_pipe: - return (getLangOpts().OpenCL && getLangOpts().OpenCLVersion >= 200) || - getLangOpts().OpenCLCPlusPlus; + return getLangOpts().OpenCLPipe; case tok::identifier: // foo::bar // Unfortunate hack to support "Class.factoryMethod" notation. @@ -5180,6 +5247,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_friend: // static_assert-declaration + case tok::kw_static_assert: case tok::kw__Static_assert: // GNU typeof support. @@ -5448,11 +5516,12 @@ void Parser::ParseTypeQualifierListOpt( switch (Tok.getKind()) { case tok::code_completion: + cutOffParsing(); if (CodeCompletionHandler) (*CodeCompletionHandler)(); else Actions.CodeCompleteTypeQualifiers(DS); - return cutOffParsing(); + return; case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID, @@ -5587,8 +5656,7 @@ static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang, if (Kind == tok::star || Kind == tok::caret) return true; - if (Kind == tok::kw_pipe && - ((Lang.OpenCL && Lang.OpenCLVersion >= 200) || Lang.OpenCLCPlusPlus)) + if (Kind == tok::kw_pipe && Lang.OpenCLPipe) return true; if (!Lang.CPlusPlus) @@ -6990,8 +7058,9 @@ void Parser::ParseBracketDeclarator(Declarator &D) { std::move(attrs), T.getCloseLocation()); return; } else if (Tok.getKind() == tok::code_completion) { + cutOffParsing(); Actions.CodeCompleteBracketDeclarator(getCurScope()); - return cutOffParsing(); + return; } // If valid, this location is the position where we read the 'static' keyword. @@ -7274,6 +7343,7 @@ bool Parser::TryAltiVecVectorTokenOutOfLine() { case tok::kw_float: case tok::kw_double: case tok::kw_bool: + case tok::kw__Bool: case tok::kw___bool: case tok::kw___pixel: Tok.setKind(tok::kw___vector); @@ -7283,7 +7353,8 @@ bool Parser::TryAltiVecVectorTokenOutOfLine() { Tok.setKind(tok::kw___vector); return true; } - if (Next.getIdentifierInfo() == Ident_bool) { + if (Next.getIdentifierInfo() == Ident_bool || + Next.getIdentifierInfo() == Ident_Bool) { Tok.setKind(tok::kw___vector); return true; } @@ -7308,6 +7379,7 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, case tok::kw_float: case tok::kw_double: case tok::kw_bool: + case tok::kw__Bool: case tok::kw___bool: case tok::kw___pixel: isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID, Policy); @@ -7317,8 +7389,10 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID,Policy); return true; } - if (Next.getIdentifierInfo() == Ident_bool) { - isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID,Policy); + if (Next.getIdentifierInfo() == Ident_bool || + Next.getIdentifierInfo() == Ident_Bool) { + isInvalid = + DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID, Policy); return true; } break; diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 88ebb59f9a60..ca5c013a51fe 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -63,8 +63,8 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context, ObjCDeclContextSwitch ObjCDC(*this); if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteNamespaceDecl(getCurScope()); cutOffParsing(); + Actions.CodeCompleteNamespaceDecl(getCurScope()); return nullptr; } @@ -132,7 +132,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context, << FixItHint::CreateRemoval(InlineLoc); Decl *NSAlias = ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd); return Actions.ConvertDeclToDeclGroup(NSAlias); -} + } BalancedDelimiterTracker T(*this, tok::l_brace); if (T.consumeOpen()) { @@ -283,8 +283,8 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, ConsumeToken(); // eat the '='. if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteNamespaceAliasDecl(getCurScope()); cutOffParsing(); + Actions.CodeCompleteNamespaceAliasDecl(getCurScope()); return nullptr; } @@ -471,8 +471,8 @@ Parser::ParseUsingDirectiveOrDeclaration(DeclaratorContext Context, SourceLocation UsingLoc = ConsumeToken(); if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteUsing(getCurScope()); cutOffParsing(); + Actions.CodeCompleteUsing(getCurScope()); return nullptr; } @@ -497,11 +497,7 @@ Parser::ParseUsingDirectiveOrDeclaration(DeclaratorContext Context, } // Otherwise, it must be a using-declaration or an alias-declaration. - - // Using declarations can't have attributes. - ProhibitAttributes(attrs); - - return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd, + return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd, attrs, AS_none); } @@ -525,8 +521,8 @@ Decl *Parser::ParseUsingDirective(DeclaratorContext Context, SourceLocation NamespcLoc = ConsumeToken(); if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteUsingDirective(getCurScope()); cutOffParsing(); + Actions.CodeCompleteUsingDirective(getCurScope()); return nullptr; } @@ -627,7 +623,8 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context, if (getLangOpts().CPlusPlus11 && Context == DeclaratorContext::Member && Tok.is(tok::identifier) && (NextToken().is(tok::semi) || NextToken().is(tok::comma) || - NextToken().is(tok::ellipsis)) && + NextToken().is(tok::ellipsis) || NextToken().is(tok::l_square) || + NextToken().is(tok::kw___attribute)) && D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() && !D.SS.getScopeRep()->getAsNamespace() && !D.SS.getScopeRep()->getAsNamespaceAlias()) { @@ -670,11 +667,48 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context, /// alias-declaration: C++11 [dcl.dcl]p1 /// 'using' identifier attribute-specifier-seq[opt] = type-id ; /// +/// using-enum-declaration: [C++20, dcl.enum] +/// 'using' elaborated-enum-specifier ; +/// +/// elaborated-enum-specifier: +/// 'enum' nested-name-specifier[opt] identifier Parser::DeclGroupPtrTy -Parser::ParseUsingDeclaration(DeclaratorContext Context, - const ParsedTemplateInfo &TemplateInfo, - SourceLocation UsingLoc, SourceLocation &DeclEnd, - AccessSpecifier AS) { +Parser::ParseUsingDeclaration( + DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, + SourceLocation UsingLoc, SourceLocation &DeclEnd, + ParsedAttributesWithRange &PrefixAttrs, AccessSpecifier AS) { + SourceLocation UELoc; + if (TryConsumeToken(tok::kw_enum, UELoc)) { + // C++20 using-enum + Diag(UELoc, getLangOpts().CPlusPlus20 + ? diag::warn_cxx17_compat_using_enum_declaration + : diag::ext_using_enum_declaration); + + DiagnoseCXX11AttributeExtension(PrefixAttrs); + + DeclSpec DS(AttrFactory); + ParseEnumSpecifier(UELoc, DS, TemplateInfo, AS, + // DSC_trailing has the semantics we desire + DeclSpecContext::DSC_trailing); + + if (TemplateInfo.Kind) { + SourceRange R = TemplateInfo.getSourceRange(); + Diag(UsingLoc, diag::err_templated_using_directive_declaration) + << 1 /* declaration */ << R << FixItHint::CreateRemoval(R); + + return nullptr; + } + + Decl *UED = Actions.ActOnUsingEnumDeclaration(getCurScope(), AS, UsingLoc, + UELoc, DS); + DeclEnd = Tok.getLocation(); + if (ExpectAndConsume(tok::semi, diag::err_expected_after, + "using-enum declaration")) + SkipUntil(tok::semi); + + return Actions.ConvertDeclToDeclGroup(UED); + } + // Check for misplaced attributes before the identifier in an // alias-declaration. ParsedAttributesWithRange MisplacedAttrs(AttrFactory); @@ -684,8 +718,18 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context, bool InvalidDeclarator = ParseUsingDeclarator(Context, D); ParsedAttributesWithRange Attrs(AttrFactory); - MaybeParseGNUAttributes(Attrs); - MaybeParseCXX11Attributes(Attrs); + MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs); + + // If we had any misplaced attributes from earlier, this is where they + // should have been written. + if (MisplacedAttrs.Range.isValid()) { + Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed) + << FixItHint::CreateInsertionFromRange( + Tok.getLocation(), + CharSourceRange::getTokenRange(MisplacedAttrs.Range)) + << FixItHint::CreateRemoval(MisplacedAttrs.Range); + Attrs.takeAllFrom(MisplacedAttrs); + } // Maybe this is an alias-declaration. if (Tok.is(tok::equal)) { @@ -694,16 +738,7 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context, return nullptr; } - // If we had any misplaced attributes from earlier, this is where they - // should have been written. - if (MisplacedAttrs.Range.isValid()) { - Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed) - << FixItHint::CreateInsertionFromRange( - Tok.getLocation(), - CharSourceRange::getTokenRange(MisplacedAttrs.Range)) - << FixItHint::CreateRemoval(MisplacedAttrs.Range); - Attrs.takeAllFrom(MisplacedAttrs); - } + ProhibitAttributes(PrefixAttrs); Decl *DeclFromDeclSpec = nullptr; Decl *AD = ParseAliasDeclarationAfterDeclarator( @@ -711,10 +746,7 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context, return Actions.ConvertDeclToDeclGroup(AD, DeclFromDeclSpec); } - // C++11 attributes are not allowed on a using-declaration, but GNU ones - // are. - ProhibitAttributes(MisplacedAttrs); - ProhibitAttributes(Attrs); + DiagnoseCXX11AttributeExtension(PrefixAttrs); // Diagnose an attempt to declare a templated using-declaration. // In C++11, alias-declarations can be templates: @@ -732,8 +764,10 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context, SmallVector<Decl *, 8> DeclsInGroup; while (true) { - // Parse (optional) attributes (most likely GNU strong-using extension). - MaybeParseGNUAttributes(Attrs); + // Parse (optional) attributes. + MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs); + DiagnoseCXX11AttributeExtension(Attrs); + Attrs.addAll(PrefixAttrs.begin(), PrefixAttrs.end()); if (InvalidDeclarator) SkipUntil(tok::comma, tok::semi, StopBeforeMatch); @@ -772,8 +806,9 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context, // Eat ';'. DeclEnd = Tok.getLocation(); if (ExpectAndConsume(tok::semi, diag::err_expected_after, - !Attrs.empty() ? "attributes list" - : "using declaration")) + !Attrs.empty() ? "attributes list" + : UELoc.isValid() ? "using-enum declaration" + : "using declaration")) SkipUntil(tok::semi); return Actions.BuildDeclaratorGroup(DeclsInGroup); @@ -857,6 +892,16 @@ Decl *Parser::ParseAliasDeclarationAfterDeclarator( DeclFromDeclSpec); } +static FixItHint getStaticAssertNoMessageFixIt(const Expr *AssertExpr, + SourceLocation EndExprLoc) { + if (const auto *BO = dyn_cast_or_null<BinaryOperator>(AssertExpr)) { + if (BO->getOpcode() == BO_LAnd && + isa<StringLiteral>(BO->getRHS()->IgnoreImpCasts())) + return FixItHint::CreateReplacement(BO->getOperatorLoc(), ","); + } + return FixItHint::CreateInsertion(EndExprLoc, ", \"\""); +} + /// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration. /// /// [C++0x] static_assert-declaration: @@ -871,8 +916,13 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ if (Tok.is(tok::kw__Static_assert) && !getLangOpts().C11) Diag(Tok, diag::ext_c11_feature) << Tok.getName(); - if (Tok.is(tok::kw_static_assert)) - Diag(Tok, diag::warn_cxx98_compat_static_assert); + if (Tok.is(tok::kw_static_assert)) { + if (!getLangOpts().CPlusPlus) + Diag(Tok, diag::ext_ms_static_assert) + << FixItHint::CreateReplacement(Tok.getLocation(), "_Static_assert"); + else + Diag(Tok, diag::warn_cxx98_compat_static_assert); + } SourceLocation StaticAssertLoc = ConsumeToken(); @@ -893,12 +943,17 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ ExprResult AssertMessage; if (Tok.is(tok::r_paren)) { - Diag(Tok, getLangOpts().CPlusPlus17 - ? diag::warn_cxx14_compat_static_assert_no_message - : diag::ext_static_assert_no_message) - << (getLangOpts().CPlusPlus17 - ? FixItHint() - : FixItHint::CreateInsertion(Tok.getLocation(), ", \"\"")); + unsigned DiagVal; + if (getLangOpts().CPlusPlus17) + DiagVal = diag::warn_cxx14_compat_static_assert_no_message; + else if (getLangOpts().CPlusPlus) + DiagVal = diag::ext_cxx_static_assert_no_message; + else if (getLangOpts().C2x) + DiagVal = diag::warn_c17_compat_static_assert_no_message; + else + DiagVal = diag::ext_c_static_assert_no_message; + Diag(Tok, DiagVal) << getStaticAssertNoMessageFixIt(AssertExpr.get(), + Tok.getLocation()); } else { if (ExpectAndConsume(tok::comma)) { SkipUntil(tok::semi); @@ -1414,8 +1469,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (Tok.is(tok::code_completion)) { // Code completion for a struct, class, or union name. + cutOffParsing(); Actions.CodeCompleteTag(getCurScope(), TagType); - return cutOffParsing(); + return; } // C++03 [temp.explicit] 14.7.2/8: @@ -1435,8 +1491,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, ParsedAttributesWithRange attrs(AttrFactory); // If attributes exist after tag, parse them. - MaybeParseGNUAttributes(attrs); - MaybeParseMicrosoftDeclSpecs(attrs); + MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs); // Parse inheritance specifiers. if (Tok.isOneOf(tok::kw___single_inheritance, @@ -1444,10 +1499,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, tok::kw___virtual_inheritance)) ParseMicrosoftInheritanceClassAttributes(attrs); - // If C++0x attributes exist here, parse them. - // FIXME: Are we consistent with the ordering of parsing of different - // styles of attributes? - MaybeParseCXX11Attributes(attrs); + // Allow attributes to precede or succeed the inheritance specifiers. + MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs); // Source location used by FIXIT to insert misplaced // C++11 attributes @@ -1693,7 +1746,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TUK = Sema::TUK_Reference; else if (Tok.is(tok::l_brace) || (getLangOpts().CPlusPlus && Tok.is(tok::colon)) || - (isCXX11FinalKeyword() && + (isClassCompatibleKeyword() && (NextToken().is(tok::l_brace) || NextToken().is(tok::colon)))) { if (DS.isFriendSpecified()) { // C++ [class.friend]p2: @@ -1709,14 +1762,18 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Okay, this is a class definition. TUK = Sema::TUK_Definition; } - } else if (isCXX11FinalKeyword() && (NextToken().is(tok::l_square) || - NextToken().is(tok::kw_alignas))) { + } else if (isClassCompatibleKeyword() && + (NextToken().is(tok::l_square) || + NextToken().is(tok::kw_alignas) || + isCXX11VirtSpecifier(NextToken()) != VirtSpecifiers::VS_None)) { // We can't tell if this is a definition or reference // until we skipped the 'final' and C++11 attribute specifiers. TentativeParsingAction PA(*this); - // Skip the 'final' keyword. - ConsumeToken(); + // Skip the 'final', abstract'... keywords. + while (isClassCompatibleKeyword()) { + ConsumeToken(); + } // Skip C++11 attribute specifiers. while (true) { @@ -1819,7 +1876,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Sema::TUK_Declaration) { // This is an explicit instantiation of a class template. - ProhibitAttributes(attrs); + ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, + /*DiagnoseEmptyAttrs=*/true); TagOrTempResult = Actions.ActOnExplicitInstantiation( getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, @@ -1834,7 +1892,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } else if (TUK == Sema::TUK_Reference || (TUK == Sema::TUK_Friend && TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { - ProhibitAttributes(attrs); + ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, + /*DiagnoseEmptyAttrs=*/true); TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc, SS, TemplateId->TemplateKWLoc, @@ -1906,7 +1965,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TagType, StartLoc, SS, Name, NameLoc, attrs); } else if (TUK == Sema::TUK_Friend && TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) { - ProhibitAttributes(attrs); + ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, + /*DiagnoseEmptyAttrs=*/true); TagOrTempResult = Actions.ActOnTemplatedFriendTag( getCurScope(), DS.getFriendSpecLoc(), TagType, StartLoc, SS, Name, @@ -1915,7 +1975,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateParams ? TemplateParams->size() : 0)); } else { if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition) - ProhibitAttributes(attrs); + ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, + /* DiagnoseEmptyAttrs=*/true); if (TUK == Sema::TUK_Definition && TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { @@ -1961,7 +2022,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (TUK == Sema::TUK_Definition) { assert(Tok.is(tok::l_brace) || (getLangOpts().CPlusPlus && Tok.is(tok::colon)) || - isCXX11FinalKeyword()); + isClassCompatibleKeyword()); if (SkipBody.ShouldSkip) SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType, TagOrTempResult.get()); @@ -2228,8 +2289,10 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const { Ident_final = &PP.getIdentifierTable().get("final"); if (getLangOpts().GNUKeywords) Ident_GNU_final = &PP.getIdentifierTable().get("__final"); - if (getLangOpts().MicrosoftExt) + if (getLangOpts().MicrosoftExt) { Ident_sealed = &PP.getIdentifierTable().get("sealed"); + Ident_abstract = &PP.getIdentifierTable().get("abstract"); + } Ident_override = &PP.getIdentifierTable().get("override"); } @@ -2239,6 +2302,9 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const { if (II == Ident_sealed) return VirtSpecifiers::VS_Sealed; + if (II == Ident_abstract) + return VirtSpecifiers::VS_Abstract; + if (II == Ident_final) return VirtSpecifiers::VS_Final; @@ -2284,6 +2350,8 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, << VirtSpecifiers::getSpecifierName(Specifier); } else if (Specifier == VirtSpecifiers::VS_Sealed) { Diag(Tok.getLocation(), diag::ext_ms_sealed_keyword); + } else if (Specifier == VirtSpecifiers::VS_Abstract) { + Diag(Tok.getLocation(), diag::ext_ms_abstract_keyword); } else if (Specifier == VirtSpecifiers::VS_GNU_Final) { Diag(Tok.getLocation(), diag::ext_warn_gnu_final); } else { @@ -2306,6 +2374,16 @@ bool Parser::isCXX11FinalKeyword() const { Specifier == VirtSpecifiers::VS_Sealed; } +/// isClassCompatibleKeyword - Determine whether the next token is a C++11 +/// 'final' or Microsoft 'sealed' or 'abstract' contextual keywords. +bool Parser::isClassCompatibleKeyword() const { + VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(); + return Specifier == VirtSpecifiers::VS_Final || + Specifier == VirtSpecifiers::VS_GNU_Final || + Specifier == VirtSpecifiers::VS_Sealed || + Specifier == VirtSpecifiers::VS_Abstract; +} + /// Parse a C++ member-declarator up to, but not including, the optional /// brace-or-equal-initializer or pure-specifier. bool Parser::ParseCXXMemberDeclaratorBeforeInitializer( @@ -2589,6 +2667,13 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParsedAttributesViewWithRange FnAttrs; // Optional C++11 attribute-specifier MaybeParseCXX11Attributes(attrs); + + // The next token may be an OpenMP pragma annotation token. That would + // normally be handled from ParseCXXClassMemberDeclarationWithPragmas, but in + // this case, it came from an *attribute* rather than a pragma. Handle it now. + if (Tok.is(tok::annot_attr_openmp)) + return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs); + // We need to keep these attributes for future diagnostic // before they are taken over by declaration specifier. FnAttrs.addAll(attrs.begin(), attrs.end()); @@ -2597,8 +2682,6 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, MaybeParseMicrosoftAttributes(attrs); if (Tok.is(tok::kw_using)) { - ProhibitAttributes(attrs); - // Eat 'using'. SourceLocation UsingLoc = ConsumeToken(); @@ -2617,7 +2700,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SourceLocation DeclEnd; // Otherwise, it must be a using-declaration or an alias-declaration. return ParseUsingDeclaration(DeclaratorContext::Member, TemplateInfo, - UsingLoc, DeclEnd, AS); + UsingLoc, DeclEnd, attrs, AS); } // Hold late-parsed attributes so we can attach a Decl to them later. @@ -2733,8 +2816,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, else if (KW.is(tok::kw_delete)) DefinitionKind = FunctionDefinitionKind::Deleted; else if (KW.is(tok::code_completion)) { - Actions.CodeCompleteAfterFunctionEquals(DeclaratorInfo); cutOffParsing(); + Actions.CodeCompleteAfterFunctionEquals(DeclaratorInfo); return nullptr; } } @@ -2872,8 +2955,13 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, HasStaticInitializer = true; } + if (PureSpecLoc.isValid() && VS.getAbstractLoc().isValid()) { + Diag(PureSpecLoc, diag::err_duplicate_virt_specifier) << "abstract"; + } if (ThisDecl && PureSpecLoc.isValid()) Actions.ActOnPureSpecifier(ThisDecl, PureSpecLoc); + else if (ThisDecl && VS.getAbstractLoc().isValid()) + Actions.ActOnPureSpecifier(ThisDecl, VS.getAbstractLoc()); // Handle the initializer. if (HasInClassInit != ICIS_NoInit) { @@ -3180,6 +3268,7 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( return nullptr; } + case tok::annot_attr_openmp: case tok::annot_pragma_openmp: return ParseOpenMPDeclarativeDirectiveWithExtDecl( AS, AccessAttrs, /*Delayed=*/true, TagType, TagDecl); @@ -3258,30 +3347,53 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); SourceLocation FinalLoc; + SourceLocation AbstractLoc; bool IsFinalSpelledSealed = false; + bool IsAbstract = false; // Parse the optional 'final' keyword. if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) { - VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(Tok); - assert((Specifier == VirtSpecifiers::VS_Final || - Specifier == VirtSpecifiers::VS_GNU_Final || - Specifier == VirtSpecifiers::VS_Sealed) && + while (true) { + VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(Tok); + if (Specifier == VirtSpecifiers::VS_None) + break; + if (isCXX11FinalKeyword()) { + if (FinalLoc.isValid()) { + auto Skipped = ConsumeToken(); + Diag(Skipped, diag::err_duplicate_class_virt_specifier) + << VirtSpecifiers::getSpecifierName(Specifier); + } else { + FinalLoc = ConsumeToken(); + if (Specifier == VirtSpecifiers::VS_Sealed) + IsFinalSpelledSealed = true; + } + } else { + if (AbstractLoc.isValid()) { + auto Skipped = ConsumeToken(); + Diag(Skipped, diag::err_duplicate_class_virt_specifier) + << VirtSpecifiers::getSpecifierName(Specifier); + } else { + AbstractLoc = ConsumeToken(); + IsAbstract = true; + } + } + if (TagType == DeclSpec::TST_interface) + Diag(FinalLoc, diag::err_override_control_interface) + << VirtSpecifiers::getSpecifierName(Specifier); + else if (Specifier == VirtSpecifiers::VS_Final) + Diag(FinalLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_override_control_keyword + : diag::ext_override_control_keyword) + << VirtSpecifiers::getSpecifierName(Specifier); + else if (Specifier == VirtSpecifiers::VS_Sealed) + Diag(FinalLoc, diag::ext_ms_sealed_keyword); + else if (Specifier == VirtSpecifiers::VS_Abstract) + Diag(AbstractLoc, diag::ext_ms_abstract_keyword); + else if (Specifier == VirtSpecifiers::VS_GNU_Final) + Diag(FinalLoc, diag::ext_warn_gnu_final); + } + assert((FinalLoc.isValid() || AbstractLoc.isValid()) && "not a class definition"); - FinalLoc = ConsumeToken(); - IsFinalSpelledSealed = Specifier == VirtSpecifiers::VS_Sealed; - - if (TagType == DeclSpec::TST_interface) - Diag(FinalLoc, diag::err_override_control_interface) - << VirtSpecifiers::getSpecifierName(Specifier); - else if (Specifier == VirtSpecifiers::VS_Final) - Diag(FinalLoc, getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_override_control_keyword - : diag::ext_override_control_keyword) - << VirtSpecifiers::getSpecifierName(Specifier); - else if (Specifier == VirtSpecifiers::VS_Sealed) - Diag(FinalLoc, diag::ext_ms_sealed_keyword); - else if (Specifier == VirtSpecifiers::VS_GNU_Final) - Diag(FinalLoc, diag::ext_warn_gnu_final); // Parse any C++11 attributes after 'final' keyword. // These attributes are not allowed to appear here, @@ -3354,7 +3466,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (TagDecl) Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc, - IsFinalSpelledSealed, + IsFinalSpelledSealed, IsAbstract, T.getOpenLocation()); // C++ 11p3: Members of a class defined with the keyword class are private @@ -3401,15 +3513,6 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // declarations and the lexed inline method definitions, along with any // delayed attributes. - // Save the state of Sema.FPFeatures, and change the setting - // to the levels specified on the command line. Previous level - // will be restored when the RAII object is destroyed. - Sema::FPFeaturesStateRAII SaveFPFeaturesState(Actions); - FPOptionsOverride NewOverrides; - Actions.CurFPFeatures = NewOverrides.applyOverrides(getLangOpts()); - Actions.FpPragmaStack.Act(Tok.getLocation(), Sema::PSK_Reset, StringRef(), - {} /*unused*/); - SourceLocation SavedPrevTokLocation = PrevTokLocation; ParseLexedPragmas(getCurrentClass()); ParseLexedAttributes(getCurrentClass()); @@ -3491,9 +3594,10 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { do { if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteConstructorInitializer(ConstructorDecl, MemInitializers); - return cutOffParsing(); + return; } MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); @@ -4039,6 +4143,70 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { } } +void Parser::ParseOpenMPAttributeArgs(IdentifierInfo *AttrName, + CachedTokens &OpenMPTokens) { + // Both 'sequence' and 'directive' attributes require arguments, so parse the + // open paren for the argument list. + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { + Diag(Tok, diag::err_expected) << tok::l_paren; + return; + } + + if (AttrName->isStr("directive")) { + // If the attribute is named `directive`, we can consume its argument list + // and push the tokens from it into the cached token stream for a new OpenMP + // pragma directive. + Token OMPBeginTok; + OMPBeginTok.startToken(); + OMPBeginTok.setKind(tok::annot_attr_openmp); + OMPBeginTok.setLocation(Tok.getLocation()); + OpenMPTokens.push_back(OMPBeginTok); + + ConsumeAndStoreUntil(tok::r_paren, OpenMPTokens, /*StopAtSemi=*/false, + /*ConsumeFinalToken*/ false); + Token OMPEndTok; + OMPEndTok.startToken(); + OMPEndTok.setKind(tok::annot_pragma_openmp_end); + OMPEndTok.setLocation(Tok.getLocation()); + OpenMPTokens.push_back(OMPEndTok); + } else { + assert(AttrName->isStr("sequence") && + "Expected either 'directive' or 'sequence'"); + // If the attribute is named 'sequence', its argument is a list of one or + // more OpenMP attributes (either 'omp::directive' or 'omp::sequence', + // where the 'omp::' is optional). + do { + // We expect to see one of the following: + // * An identifier (omp) for the attribute namespace followed by :: + // * An identifier (directive) or an identifier (sequence). + SourceLocation IdentLoc; + IdentifierInfo *Ident = TryParseCXX11AttributeIdentifier(IdentLoc); + + // If there is an identifier and it is 'omp', a double colon is required + // followed by the actual identifier we're after. + if (Ident && Ident->isStr("omp") && !ExpectAndConsume(tok::coloncolon)) + Ident = TryParseCXX11AttributeIdentifier(IdentLoc); + + // If we failed to find an identifier (scoped or otherwise), or we found + // an unexpected identifier, diagnose. + if (!Ident || (!Ident->isStr("directive") && !Ident->isStr("sequence"))) { + Diag(Tok.getLocation(), diag::err_expected_sequence_or_directive); + SkipUntil(tok::r_paren, StopBeforeMatch); + continue; + } + // We read an identifier. If the identifier is one of the ones we + // expected, we can recurse to parse the args. + ParseOpenMPAttributeArgs(Ident, OpenMPTokens); + + // There may be a comma to signal that we expect another directive in the + // sequence. + } while (TryConsumeToken(tok::comma)); + } + // Parse the closing paren for the argument list. + T.consumeClose(); +} + static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName, IdentifierInfo *ScopeName) { switch ( @@ -4079,7 +4247,8 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, - SourceLocation ScopeLoc) { + SourceLocation ScopeLoc, + CachedTokens &OpenMPTokens) { assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list"); SourceLocation LParenLoc = Tok.getLocation(); const LangOptions &LO = getLangOpts(); @@ -4104,6 +4273,18 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, return true; } + if (ScopeName && ScopeName->isStr("omp")) { + Diag(AttrNameLoc, getLangOpts().OpenMP >= 51 + ? diag::warn_omp51_compat_attributes + : diag::ext_omp_attributes); + + ParseOpenMPAttributeArgs(AttrName, OpenMPTokens); + + // We claim that an attribute was parsed and added so that one is not + // created for us by the caller. + return true; + } + unsigned NumArgs; // Some Clang-scoped attributes have some special parsing behavior. if (ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang"))) @@ -4163,11 +4344,12 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, /// /// [C++11] attribute-namespace: /// identifier -void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, - SourceLocation *endLoc) { +void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, + CachedTokens &OpenMPTokens, + SourceLocation *EndLoc) { if (Tok.is(tok::kw_alignas)) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas); - ParseAlignmentSpecifier(attrs, endLoc); + ParseAlignmentSpecifier(Attrs, EndLoc); return; } @@ -4200,10 +4382,21 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, llvm::SmallDenseMap<IdentifierInfo*, SourceLocation, 4> SeenAttrs; - while (Tok.isNot(tok::r_square)) { - // attribute not present - if (TryConsumeToken(tok::comma)) - continue; + bool AttrParsed = false; + while (!Tok.isOneOf(tok::r_square, tok::semi)) { + if (AttrParsed) { + // If we parsed an attribute, a comma is required before parsing any + // additional attributes. + if (ExpectAndConsume(tok::comma)) { + SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch); + continue; + } + AttrParsed = false; + } + + // Eat all remaining superfluous commas before parsing the next attribute. + while (TryConsumeToken(tok::comma)) + ; SourceLocation ScopeLoc, AttrLoc; IdentifierInfo *ScopeName = nullptr, *AttrName = nullptr; @@ -4236,38 +4429,39 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, } } - bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName); - bool AttrParsed = false; - - if (StandardAttr && - !SeenAttrs.insert(std::make_pair(AttrName, AttrLoc)).second) - Diag(AttrLoc, diag::err_cxx11_attribute_repeated) - << AttrName << SourceRange(SeenAttrs[AttrName]); - // Parse attribute arguments if (Tok.is(tok::l_paren)) - AttrParsed = ParseCXX11AttributeArgs(AttrName, AttrLoc, attrs, endLoc, - ScopeName, ScopeLoc); + AttrParsed = ParseCXX11AttributeArgs(AttrName, AttrLoc, Attrs, EndLoc, + ScopeName, ScopeLoc, OpenMPTokens); - if (!AttrParsed) - attrs.addNew( + if (!AttrParsed) { + Attrs.addNew( AttrName, SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, AttrLoc), ScopeName, ScopeLoc, nullptr, 0, getLangOpts().CPlusPlus ? ParsedAttr::AS_CXX11 : ParsedAttr::AS_C2x); + AttrParsed = true; + } if (TryConsumeToken(tok::ellipsis)) Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis) << AttrName; } + // If we hit an error and recovered by parsing up to a semicolon, eat the + // semicolon and don't issue further diagnostics about missing brackets. + if (Tok.is(tok::semi)) { + ConsumeToken(); + return; + } + SourceLocation CloseLoc = Tok.getLocation(); if (ExpectAndConsume(tok::r_square)) SkipUntil(tok::r_square); else if (Tok.is(tok::r_square)) checkCompoundToken(CloseLoc, tok::r_square, CompoundToken::AttrEnd); - if (endLoc) - *endLoc = Tok.getLocation(); + if (EndLoc) + *EndLoc = Tok.getLocation(); if (ExpectAndConsume(tok::r_square)) SkipUntil(tok::r_square); } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 6acf76d713fd..22f3b7624c45 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -159,9 +159,9 @@ 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)) { + cutOffParsing(); Actions.CodeCompleteExpression(getCurScope(), PreferredType.get(Tok.getLocation())); - cutOffParsing(); return ExprError(); } @@ -1156,9 +1156,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, ConsumeToken(); if (Tok.is(tok::code_completion) && &II != Ident_super) { + cutOffParsing(); Actions.CodeCompleteObjCClassPropertyRefExpr( getCurScope(), II, ILoc, ExprStatementTokLoc == ILoc); - cutOffParsing(); return ExprError(); } // Allow either an identifier or the keyword 'class' (in C++). @@ -1469,6 +1469,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, case tok::kw_this: Res = ParseCXXThis(); break; + case tok::kw___builtin_sycl_unique_stable_name: + Res = ParseSYCLUniqueStableNameExpression(); + break; case tok::annot_typename: if (isStartOfObjCClassMessageMissingOpenBracket()) { @@ -1724,9 +1727,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, Res = ParseBlockLiteralExpression(); break; case tok::code_completion: { + cutOffParsing(); Actions.CodeCompleteExpression(getCurScope(), PreferredType.get(Tok.getLocation())); - cutOffParsing(); return ExprError(); } case tok::l_square: @@ -1807,7 +1810,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, // These can be followed by postfix-expr pieces. PreferredType = SavedType; Res = ParsePostfixExpressionSuffix(Res); - if (getLangOpts().OpenCL) + if (getLangOpts().OpenCL && + !getActions().getOpenCLOptions().isAvailableOption( + "__cl_clang_function_pointers", getLangOpts())) if (Expr *PostfixExpr = Res.get()) { QualType Ty = PostfixExpr->getType(); if (!Ty.isNull() && Ty->isFunctionType()) { @@ -1854,9 +1859,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (InMessageExpression) return LHS; + cutOffParsing(); Actions.CodeCompletePostfixExpression( getCurScope(), LHS, PreferredType.get(Tok.getLocation())); - cutOffParsing(); return ExprError(); case tok::identifier: @@ -2138,12 +2143,12 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { CorrectedBase = Base; // Code completion for a member access expression. + cutOffParsing(); Actions.CodeCompleteMemberReferenceExpr( getCurScope(), Base, CorrectedBase, OpLoc, OpKind == tok::arrow, Base && ExprStatementTokLoc == Base->getBeginLoc(), PreferredType.get(Tok.getLocation())); - cutOffParsing(); return ExprError(); } @@ -2322,6 +2327,33 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, return Operand; } +/// Parse a __builtin_sycl_unique_stable_name expression. Accepts a type-id as +/// a parameter. +ExprResult Parser::ParseSYCLUniqueStableNameExpression() { + assert(Tok.is(tok::kw___builtin_sycl_unique_stable_name) && + "Not __bulitin_sycl_unique_stable_name"); + + SourceLocation OpLoc = ConsumeToken(); + BalancedDelimiterTracker T(*this, tok::l_paren); + + // __builtin_sycl_unique_stable_name expressions are always parenthesized. + if (T.expectAndConsume(diag::err_expected_lparen_after, + "__builtin_sycl_unique_stable_name")) + return ExprError(); + + TypeResult Ty = ParseTypeName(); + + if (Ty.isInvalid()) { + T.skipToEnd(); + return ExprError(); + } + + if (T.consumeClose()) + return ExprError(); + + return Actions.ActOnSYCLUniqueStableNameExpr(OpLoc, T.getOpenLocation(), + T.getCloseLocation(), Ty.get()); +} /// Parse a sizeof or alignof expression. /// @@ -2776,10 +2808,10 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, CastTy = nullptr; if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteExpression( getCurScope(), PreferredType.get(Tok.getLocation()), /*IsParenthesized=*/ExprType >= CompoundLiteral); - cutOffParsing(); return ExprError(); } @@ -3410,8 +3442,9 @@ Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs, /// \endverbatim void Parser::ParseBlockId(SourceLocation CaretLoc) { if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); - return cutOffParsing(); + return; } // Parse the specifier-qualifier-list piece. @@ -3596,8 +3629,8 @@ Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() { } else { // Parse the platform name. if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteAvailabilityPlatformName(); cutOffParsing(); + Actions.CodeCompleteAvailabilityPlatformName(); return None; } if (Tok.isNot(tok::identifier)) { diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 4b5703d79f28..f3d10b4a0889 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -9,7 +9,6 @@ // This file implements the Expression parsing implementation for C++. // //===----------------------------------------------------------------------===// -#include "clang/Parse/Parser.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclTemplate.h" @@ -17,6 +16,7 @@ #include "clang/Basic/PrettyStackTrace.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" @@ -235,6 +235,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier( while (true) { if (HasScopeSpecifier) { if (Tok.is(tok::code_completion)) { + cutOffParsing(); // Code completion for a nested-name-specifier, where the code // completion token follows the '::'. Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext, @@ -245,7 +246,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // token will cause assertion in // Preprocessor::AnnotatePreviousCachedTokens. SS.setEndLoc(Tok.getLocation()); - cutOffParsing(); return true; } @@ -688,9 +688,9 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { /// ParseLambdaExpression - Parse a C++11 lambda expression. /// /// lambda-expression: -/// lambda-introducer lambda-declarator[opt] compound-statement +/// lambda-introducer lambda-declarator compound-statement /// lambda-introducer '<' template-parameter-list '>' -/// lambda-declarator[opt] compound-statement +/// requires-clause[opt] lambda-declarator compound-statement /// /// lambda-introducer: /// '[' lambda-capture[opt] ']' @@ -722,9 +722,13 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { /// '&' identifier initializer /// /// lambda-declarator: -/// '(' parameter-declaration-clause ')' attribute-specifier[opt] -/// 'mutable'[opt] exception-specification[opt] -/// trailing-return-type[opt] +/// lambda-specifiers [C++2b] +/// '(' parameter-declaration-clause ')' lambda-specifiers +/// requires-clause[opt] +/// +/// lambda-specifiers: +/// decl-specifier-seq[opt] noexcept-specifier[opt] +/// attribute-specifier-seq[opt] trailing-return-type[opt] /// ExprResult Parser::ParseLambdaExpression() { // Parse lambda-introducer. @@ -877,9 +881,9 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, // expression parser perform the completion. if (Tok.is(tok::code_completion) && !(getLangOpts().ObjC && Tentative)) { + cutOffParsing(); Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, /*AfterAmpersand=*/false); - cutOffParsing(); break; } @@ -891,6 +895,7 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, } if (Tok.is(tok::code_completion)) { + cutOffParsing(); // If we're in Objective-C++ and we have a bare '[', then this is more // likely to be a message receiver. if (getLangOpts().ObjC && Tentative && First) @@ -898,7 +903,6 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, else Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, /*AfterAmpersand=*/false); - cutOffParsing(); break; } @@ -943,9 +947,9 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, ConsumeToken(); if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, /*AfterAmpersand=*/true); - cutOffParsing(); break; } } @@ -1249,7 +1253,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( Actions.PushLambdaScope(); ParsedAttributes Attr(AttrFactory); - SourceLocation DeclLoc = Tok.getLocation(); if (getLangOpts().CUDA) { // In CUDA code, GNU attributes are allowed to appear immediately after the // "[...]", even if there is no "(...)" before the lambda body. @@ -1302,13 +1305,99 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( } } + // Implement WG21 P2173, which allows attributes immediately before the + // lambda declarator and applies them to the corresponding function operator + // or operator template declaration. We accept this as a conforming extension + // in all language modes that support lambdas. + if (isCXX11AttributeSpecifier()) { + Diag(Tok, getLangOpts().CPlusPlus2b + ? diag::warn_cxx20_compat_decl_attrs_on_lambda + : diag::ext_decl_attrs_on_lambda); + MaybeParseCXX11Attributes(D); + } + TypeResult TrailingReturnType; SourceLocation TrailingReturnTypeLoc; + + auto ParseLambdaSpecifiers = + [&](SourceLocation LParenLoc, SourceLocation RParenLoc, + MutableArrayRef<DeclaratorChunk::ParamInfo> ParamInfo, + SourceLocation EllipsisLoc) { + SourceLocation DeclEndLoc = RParenLoc; + + // GNU-style attributes must be parsed before the mutable specifier to + // be compatible with GCC. MSVC-style attributes must be parsed before + // the mutable specifier to be compatible with MSVC. + MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attr); + + // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update + // the DeclEndLoc. + SourceLocation MutableLoc; + SourceLocation ConstexprLoc; + SourceLocation ConstevalLoc; + tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc, + ConstevalLoc, DeclEndLoc); + + addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); + addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS); + // Parse exception-specification[opt]. + ExceptionSpecificationType ESpecType = EST_None; + SourceRange ESpecRange; + SmallVector<ParsedType, 2> DynamicExceptions; + SmallVector<SourceRange, 2> DynamicExceptionRanges; + ExprResult NoexceptExpr; + CachedTokens *ExceptionSpecTokens; + ESpecType = tryParseExceptionSpecification( + /*Delayed=*/false, ESpecRange, DynamicExceptions, + DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens); + + if (ESpecType != EST_None) + DeclEndLoc = ESpecRange.getEnd(); + + // Parse attribute-specifier[opt]. + MaybeParseCXX11Attributes(Attr, &DeclEndLoc); + + // Parse OpenCL addr space attribute. + if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local, + tok::kw___constant, tok::kw___generic)) { + ParseOpenCLQualifiers(DS.getAttributes()); + ConsumeToken(); + } + + SourceLocation FunLocalRangeEnd = DeclEndLoc; + + // Parse trailing-return-type[opt]. + if (Tok.is(tok::arrow)) { + FunLocalRangeEnd = Tok.getLocation(); + SourceRange Range; + TrailingReturnType = ParseTrailingReturnType( + Range, /*MayBeFollowedByDirectInit*/ false); + TrailingReturnTypeLoc = Range.getBegin(); + if (Range.getEnd().isValid()) + DeclEndLoc = Range.getEnd(); + } + + SourceLocation NoLoc; + D.AddTypeInfo( + DeclaratorChunk::getFunction( + /*HasProto=*/true, + /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(), + ParamInfo.size(), EllipsisLoc, RParenLoc, + /*RefQualifierIsLvalueRef=*/true, + /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType, ESpecRange, + DynamicExceptions.data(), DynamicExceptionRanges.data(), + DynamicExceptions.size(), + NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, + /*ExceptionSpecTokens*/ nullptr, + /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D, + TrailingReturnType, TrailingReturnTypeLoc, &DS), + std::move(Attr), DeclEndLoc); + }; + if (Tok.is(tok::l_paren)) { - ParseScope PrototypeScope(this, - Scope::FunctionPrototypeScope | - Scope::FunctionDeclarationScope | - Scope::DeclScope); + ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope | + Scope::FunctionDeclarationScope | + Scope::DeclScope); BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); @@ -1334,170 +1423,36 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( } T.consumeClose(); - SourceLocation RParenLoc = T.getCloseLocation(); - SourceLocation DeclEndLoc = RParenLoc; - - // GNU-style attributes must be parsed before the mutable specifier to be - // compatible with GCC. - MaybeParseGNUAttributes(Attr, &DeclEndLoc); - - // MSVC-style attributes must be parsed before the mutable specifier to be - // compatible with MSVC. - MaybeParseMicrosoftDeclSpecs(Attr, &DeclEndLoc); - - // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update the - // DeclEndLoc. - SourceLocation MutableLoc; - SourceLocation ConstexprLoc; - SourceLocation ConstevalLoc; - tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc, - ConstevalLoc, DeclEndLoc); - - addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); - addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS); - // Parse exception-specification[opt]. - ExceptionSpecificationType ESpecType = EST_None; - SourceRange ESpecRange; - SmallVector<ParsedType, 2> DynamicExceptions; - SmallVector<SourceRange, 2> DynamicExceptionRanges; - ExprResult NoexceptExpr; - CachedTokens *ExceptionSpecTokens; - ESpecType = tryParseExceptionSpecification(/*Delayed=*/false, - ESpecRange, - DynamicExceptions, - DynamicExceptionRanges, - NoexceptExpr, - ExceptionSpecTokens); - - if (ESpecType != EST_None) - DeclEndLoc = ESpecRange.getEnd(); - - // Parse attribute-specifier[opt]. - MaybeParseCXX11Attributes(Attr, &DeclEndLoc); - - // Parse OpenCL addr space attribute. - if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local, - tok::kw___constant, tok::kw___generic)) { - ParseOpenCLQualifiers(DS.getAttributes()); - ConsumeToken(); - } - - SourceLocation FunLocalRangeEnd = DeclEndLoc; - - // Parse trailing-return-type[opt]. - if (Tok.is(tok::arrow)) { - FunLocalRangeEnd = Tok.getLocation(); - SourceRange Range; - TrailingReturnType = - ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit*/ false); - TrailingReturnTypeLoc = Range.getBegin(); - if (Range.getEnd().isValid()) - DeclEndLoc = Range.getEnd(); - } - SourceLocation NoLoc; - D.AddTypeInfo(DeclaratorChunk::getFunction( - /*HasProto=*/true, - /*IsAmbiguous=*/false, LParenLoc, ParamInfo.data(), - ParamInfo.size(), EllipsisLoc, RParenLoc, - /*RefQualifierIsLvalueRef=*/true, - /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType, - ESpecRange, DynamicExceptions.data(), - DynamicExceptionRanges.data(), DynamicExceptions.size(), - NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, - /*ExceptionSpecTokens*/ nullptr, - /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D, - TrailingReturnType, TrailingReturnTypeLoc, &DS), - std::move(Attr), DeclEndLoc); + // Parse lambda-specifiers. + ParseLambdaSpecifiers(LParenLoc, /*DeclEndLoc=*/T.getCloseLocation(), + ParamInfo, EllipsisLoc); // Parse requires-clause[opt]. if (Tok.is(tok::kw_requires)) ParseTrailingRequiresClause(D); - - PrototypeScope.Exit(); - - WarnIfHasCUDATargetAttr(); } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute, tok::kw_constexpr, tok::kw_consteval, tok::kw___private, tok::kw___global, tok::kw___local, tok::kw___constant, tok::kw___generic, - tok::kw_requires) || + tok::kw_requires, tok::kw_noexcept) || (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) { - // It's common to forget that one needs '()' before 'mutable', an attribute - // specifier, the result type, or the requires clause. Deal with this. - unsigned TokKind = 0; - switch (Tok.getKind()) { - case tok::kw_mutable: TokKind = 0; break; - case tok::arrow: TokKind = 1; break; - case tok::kw___attribute: - case tok::kw___private: - case tok::kw___global: - case tok::kw___local: - case tok::kw___constant: - case tok::kw___generic: - case tok::l_square: TokKind = 2; break; - case tok::kw_constexpr: TokKind = 3; break; - case tok::kw_consteval: TokKind = 4; break; - case tok::kw_requires: TokKind = 5; break; - default: llvm_unreachable("Unknown token kind"); - } - - Diag(Tok, diag::err_lambda_missing_parens) - << TokKind - << FixItHint::CreateInsertion(Tok.getLocation(), "() "); - SourceLocation DeclEndLoc = DeclLoc; - - // GNU-style attributes must be parsed before the mutable specifier to be - // compatible with GCC. - MaybeParseGNUAttributes(Attr, &DeclEndLoc); - - // Parse 'mutable', if it's there. - SourceLocation MutableLoc; - if (Tok.is(tok::kw_mutable)) { - MutableLoc = ConsumeToken(); - DeclEndLoc = MutableLoc; - } - - // Parse attribute-specifier[opt]. - MaybeParseCXX11Attributes(Attr, &DeclEndLoc); - - // Parse the return type, if there is one. - if (Tok.is(tok::arrow)) { - SourceRange Range; - TrailingReturnType = - ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit*/ false); - if (Range.getEnd().isValid()) - DeclEndLoc = Range.getEnd(); - } + if (!getLangOpts().CPlusPlus2b) + // It's common to forget that one needs '()' before 'mutable', an + // attribute specifier, the result type, or the requires clause. Deal with + // this. + Diag(Tok, diag::ext_lambda_missing_parens) + << FixItHint::CreateInsertion(Tok.getLocation(), "() "); SourceLocation NoLoc; - D.AddTypeInfo(DeclaratorChunk::getFunction( - /*HasProto=*/true, - /*IsAmbiguous=*/false, - /*LParenLoc=*/NoLoc, - /*Params=*/nullptr, - /*NumParams=*/0, - /*EllipsisLoc=*/NoLoc, - /*RParenLoc=*/NoLoc, - /*RefQualifierIsLvalueRef=*/true, - /*RefQualifierLoc=*/NoLoc, MutableLoc, EST_None, - /*ESpecRange=*/SourceRange(), - /*Exceptions=*/nullptr, - /*ExceptionRanges=*/nullptr, - /*NumExceptions=*/0, - /*NoexceptExpr=*/nullptr, - /*ExceptionSpecTokens=*/nullptr, - /*DeclsInPrototype=*/None, DeclLoc, DeclEndLoc, D, - TrailingReturnType), - std::move(Attr), DeclEndLoc); - - // Parse the requires-clause, if present. - if (Tok.is(tok::kw_requires)) - ParseTrailingRequiresClause(D); - - WarnIfHasCUDATargetAttr(); + // Parse lambda-specifiers. + std::vector<DeclaratorChunk::ParamInfo> EmptyParamInfo; + ParseLambdaSpecifiers(/*LParenLoc=*/NoLoc, /*RParenLoc=*/NoLoc, + EmptyParamInfo, /*EllipsisLoc=*/NoLoc); } + WarnIfHasCUDATargetAttr(); + // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using // it. unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope | @@ -1979,17 +1934,36 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { /// \param FRI If non-null, a for range declaration is permitted, and if /// present will be parsed and stored here, and a null result will be returned. /// +/// \param EnterForConditionScope If true, enter a continue/break scope at the +/// appropriate moment for a 'for' loop. +/// /// \returns The parsed condition. Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, Sema::ConditionKind CK, - ForRangeInfo *FRI) { + ForRangeInfo *FRI, + bool EnterForConditionScope) { + // Helper to ensure we always enter a continue/break scope if requested. + struct ForConditionScopeRAII { + Scope *S; + void enter(bool IsConditionVariable) { + if (S) { + S->AddFlags(Scope::BreakScope | Scope::ContinueScope); + S->setIsConditionVarScope(IsConditionVariable); + } + } + ~ForConditionScopeRAII() { + if (S) + S->setIsConditionVarScope(false); + } + } ForConditionScope{EnterForConditionScope ? getCurScope() : nullptr}; + ParenBraceBracketBalancer BalancerRAIIObj(*this); PreferredType.enterCondition(Actions, Tok.getLocation()); if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition); cutOffParsing(); + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition); return Sema::ConditionError(); } @@ -2006,6 +1980,9 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, // Determine what kind of thing we have. switch (isCXXConditionDeclarationOrInitStatement(InitStmt, FRI)) { case ConditionOrInitStatement::Expression: { + // If this is a for loop, we're entering its condition. + ForConditionScope.enter(/*IsConditionVariable=*/false); + ProhibitAttributes(attrs); // We can have an empty expression here. @@ -2048,11 +2025,16 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, } case ConditionOrInitStatement::ForRangeDecl: { + // This is 'for (init-stmt; for-range-decl : range-expr)'. + // We're not actually in a for loop yet, so 'break' and 'continue' aren't + // permitted here. assert(FRI && "should not parse a for range declaration here"); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy DG = ParseSimpleDeclaration(DeclaratorContext::ForInit, DeclEnd, attrs, false, FRI); FRI->LoopVar = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); + assert((FRI->ColonLoc.isValid() || !DG) && + "cannot find for range declaration"); return Sema::ConditionResult(); } @@ -2061,6 +2043,9 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, break; } + // If this is a for loop, we're entering its condition. + ForConditionScope.enter(/*IsConditionVariable=*/true); + // type-specifier-seq DeclSpec DS(AttrFactory); DS.takeAttributesFrom(attrs); @@ -2600,10 +2585,10 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, } case tok::code_completion: { + // Don't try to parse any further. + cutOffParsing(); // Code completion for the operator name. Actions.CodeCompleteOperatorName(getCurScope()); - cutOffParsing(); - // Don't try to parse any further. return true; } @@ -2651,9 +2636,10 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, // Grab the literal operator's suffix, which will be either the next token // or a ud-suffix from the string literal. + bool IsUDSuffix = !Literal.getUDSuffix().empty(); IdentifierInfo *II = nullptr; SourceLocation SuffixLoc; - if (!Literal.getUDSuffix().empty()) { + if (IsUDSuffix) { II = &PP.getIdentifierTable().get(Literal.getUDSuffix()); SuffixLoc = Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()], @@ -2690,7 +2676,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc); - return Actions.checkLiteralOperatorId(SS, Result); + return Actions.checkLiteralOperatorId(SS, Result, IsUDSuffix); } // Parse a conversion-function-id. diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp index 9ac2b2e6f79b..9d9c03d28a97 100644 --- a/clang/lib/Parse/ParseInit.cpp +++ b/clang/lib/Parse/ParseInit.cpp @@ -159,8 +159,7 @@ static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc, /// /// \p CodeCompleteCB is called with Designation parsed so far. ExprResult Parser::ParseInitializerWithPotentialDesignator( - llvm::function_ref<void(const Designation &)> CodeCompleteCB) { - + DesignatorCompletionInfo DesignatorCompletion) { // If this is the old-style GNU extension: // designation ::= identifier ':' // Handle it as a field designator. Otherwise, this must be the start of a @@ -183,6 +182,8 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator( Designation D; D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc)); + PreferredType.enterDesignatedInitializer( + Tok.getLocation(), DesignatorCompletion.PreferredBaseType, D); return Actions.ActOnDesignatedInitializer(D, ColonLoc, true, ParseInitializer()); } @@ -199,8 +200,9 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator( SourceLocation DotLoc = ConsumeToken(); if (Tok.is(tok::code_completion)) { - CodeCompleteCB(Desig); cutOffParsing(); + Actions.CodeCompleteDesignator(DesignatorCompletion.PreferredBaseType, + DesignatorCompletion.InitExprs, Desig); return ExprError(); } if (Tok.isNot(tok::identifier)) { @@ -388,6 +390,8 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator( // Handle a normal designator sequence end, which is an equal. if (Tok.is(tok::equal)) { SourceLocation EqualLoc = ConsumeToken(); + PreferredType.enterDesignatedInitializer( + Tok.getLocation(), DesignatorCompletion.PreferredBaseType, Desig); return Actions.ActOnDesignatedInitializer(Desig, EqualLoc, false, ParseInitializer()); } @@ -396,6 +400,8 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator( // direct-list-initialization of the aggregate element. We allow this as an // extension from C++11 onwards (when direct-list-initialization was added). if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus11) { + PreferredType.enterDesignatedInitializer( + Tok.getLocation(), DesignatorCompletion.PreferredBaseType, Desig); return Actions.ActOnDesignatedInitializer(Desig, SourceLocation(), false, ParseBraceInitializer()); } @@ -453,9 +459,9 @@ ExprResult Parser::ParseBraceInitializer() { Actions, EnterExpressionEvaluationContext::InitList); bool InitExprsOk = true; - auto CodeCompleteDesignation = [&](const Designation &D) { - Actions.CodeCompleteDesignator(PreferredType.get(T.getOpenLocation()), - InitExprs, D); + DesignatorCompletionInfo DesignatorCompletion{ + InitExprs, + PreferredType.get(T.getOpenLocation()), }; while (1) { @@ -476,7 +482,7 @@ ExprResult Parser::ParseBraceInitializer() { // initializer directly. ExprResult SubElt; if (MayBeDesignationStart()) - SubElt = ParseInitializerWithPotentialDesignator(CodeCompleteDesignation); + SubElt = ParseInitializerWithPotentialDesignator(DesignatorCompletion); else SubElt = ParseInitializer(); @@ -556,9 +562,9 @@ bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs, return false; } - auto CodeCompleteDesignation = [&](const Designation &D) { - Actions.CodeCompleteDesignator(PreferredType.get(Braces.getOpenLocation()), - InitExprs, D); + DesignatorCompletionInfo DesignatorCompletion{ + InitExprs, + PreferredType.get(Braces.getOpenLocation()), }; while (!isEofOrEom()) { trailingComma = false; @@ -566,7 +572,7 @@ bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs, // initializer directly. ExprResult SubElt; if (MayBeDesignationStart()) - SubElt = ParseInitializerWithPotentialDesignator(CodeCompleteDesignation); + SubElt = ParseInitializerWithPotentialDesignator(DesignatorCompletion); else SubElt = ParseInitializer(); diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 88942ed173d0..9e145f57d61f 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -50,8 +50,8 @@ Parser::ParseObjCAtDirectives(ParsedAttributesWithRange &Attrs) { SourceLocation AtLoc = ConsumeToken(); // the "@" if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCAtDirective(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCAtDirective(getCurScope()); return nullptr; } @@ -219,8 +219,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, // Code completion after '@interface'. if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCInterfaceDecl(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCInterfaceDecl(getCurScope()); return nullptr; } @@ -253,8 +253,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, SourceLocation categoryLoc; IdentifierInfo *categoryId = nullptr; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc); cutOffParsing(); + Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc); return nullptr; } @@ -308,8 +308,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, // Code completion of superclass names. if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc); cutOffParsing(); + Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc); return nullptr; } @@ -472,8 +472,8 @@ ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs( if (Tok.is(tok::code_completion)) { // FIXME: If these aren't protocol references, we'll need different // completions. - Actions.CodeCompleteObjCProtocolReferences(protocolIdents); cutOffParsing(); + Actions.CodeCompleteObjCProtocolReferences(protocolIdents); // FIXME: Better recovery here?. return nullptr; @@ -635,10 +635,11 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, // Code completion within an Objective-C interface. if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteOrdinaryName(getCurScope(), CurParsedObjCImpl? Sema::PCC_ObjCImplementation : Sema::PCC_ObjCInterface); - return cutOffParsing(); + return; } // If we don't have an @ directive, parse it as a function definition. @@ -668,8 +669,9 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, // Otherwise, we have an @ directive, eat the @. SourceLocation AtLoc = ConsumeToken(); // the "@" if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteObjCAtDirective(getCurScope()); - return cutOffParsing(); + return; } tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID(); @@ -778,8 +780,9 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, // We break out of the big loop in two cases: when we see @end or when we see // EOF. In the former case, eat the @end. In the later case, emit an error. if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteObjCAtDirective(getCurScope()); - return cutOffParsing(); + return; } else if (Tok.isObjCAtKeyword(tok::objc_end)) { ConsumeToken(); // the "end" identifier } else { @@ -847,8 +850,9 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { while (1) { if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS); - return cutOffParsing(); + return; } const IdentifierInfo *II = Tok.getIdentifierInfo(); @@ -893,11 +897,12 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { } if (Tok.is(tok::code_completion)) { + cutOffParsing(); if (IsSetter) Actions.CodeCompleteObjCPropertySetter(getCurScope()); else Actions.CodeCompleteObjCPropertyGetter(getCurScope()); - return cutOffParsing(); + return; } SourceLocation SelLoc; @@ -1146,9 +1151,10 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, while (1) { if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteObjCPassingType( getCurScope(), DS, Context == DeclaratorContext::ObjCParameter); - return cutOffParsing(); + return; } if (Tok.isNot(tok::identifier)) @@ -1335,9 +1341,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent); if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, /*ReturnType=*/nullptr); - cutOffParsing(); return nullptr; } @@ -1350,14 +1356,13 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, // If attributes exist before the method, parse them. ParsedAttributes methodAttrs(AttrFactory); - if (getLangOpts().ObjC) - MaybeParseGNUAttributes(methodAttrs); - MaybeParseCXX11Attributes(methodAttrs); + MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0), + methodAttrs); if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, ReturnType); - cutOffParsing(); return nullptr; } @@ -1377,9 +1382,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo; if (Tok.isNot(tok::colon)) { // If attributes exist after the method, parse them. - if (getLangOpts().ObjC) - MaybeParseGNUAttributes(methodAttrs); - MaybeParseCXX11Attributes(methodAttrs); + MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0), + methodAttrs); Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); Decl *Result = Actions.ActOnMethodDeclaration( @@ -1412,19 +1416,18 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, // If attributes exist before the argument name, parse them. // Regardless, collect all the attributes we've parsed so far. - if (getLangOpts().ObjC) - MaybeParseGNUAttributes(paramAttrs); - MaybeParseCXX11Attributes(paramAttrs); + MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0), + paramAttrs); ArgInfo.ArgAttrs = paramAttrs; // Code completion for the next piece of the selector. if (Tok.is(tok::code_completion)) { + cutOffParsing(); KeyIdents.push_back(SelIdent); Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(), mType == tok::minus, /*AtParameterName=*/true, ReturnType, KeyIdents); - cutOffParsing(); return nullptr; } @@ -1444,11 +1447,11 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, // Code completion for the next piece of the selector. if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(), mType == tok::minus, /*AtParameterName=*/false, ReturnType, KeyIdents); - cutOffParsing(); return nullptr; } @@ -1496,9 +1499,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, // FIXME: Add support for optional parameter list... // If attributes exist after the method, parse them. - if (getLangOpts().ObjC) - MaybeParseGNUAttributes(methodAttrs); - MaybeParseCXX11Attributes(methodAttrs); + MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0), + methodAttrs); if (KeyIdents.size() == 0) return nullptr; @@ -1531,8 +1533,8 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, while (1) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents); cutOffParsing(); + Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents); return true; } @@ -1630,12 +1632,12 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers( } QualType BaseT = Actions.GetTypeFromParser(baseType); + cutOffParsing(); if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); } else { Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs); } - cutOffParsing(); return; } @@ -1924,8 +1926,9 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, // Set the default visibility to private. if (TryConsumeToken(tok::at)) { // parse objc-visibility-spec if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteObjCAtVisibility(getCurScope()); - return cutOffParsing(); + return; } switch (Tok.getObjCKeywordID()) { @@ -1954,9 +1957,10 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, } if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_ObjCInstanceVariableList); - return cutOffParsing(); + return; } // This needs to duplicate a small amount of code from @@ -2021,8 +2025,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, ConsumeToken(); // the "protocol" identifier if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCProtocolDecl(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCProtocolDecl(getCurScope()); return nullptr; } @@ -2105,8 +2109,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc, // Code completion after '@implementation'. if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCImplementationDecl(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCImplementationDecl(getCurScope()); return nullptr; } @@ -2143,8 +2147,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc, IdentifierInfo *categoryId = nullptr; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc); cutOffParsing(); + Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc); return nullptr; } @@ -2313,8 +2317,8 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { while (true) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCPropertyDefinition(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCPropertyDefinition(getCurScope()); return nullptr; } @@ -2331,8 +2335,8 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { if (TryConsumeToken(tok::equal)) { // property '=' ivar-name if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId); cutOffParsing(); + Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId); return nullptr; } @@ -2391,8 +2395,8 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { while (true) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCPropertyDefinition(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCPropertyDefinition(getCurScope()); return nullptr; } @@ -2728,8 +2732,8 @@ Decl *Parser::ParseObjCMethodDefinition() { StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc, ParsedStmtContext StmtCtx) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCAtStatement(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCAtStatement(getCurScope()); return StmtError(); } @@ -2769,8 +2773,8 @@ StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc, ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { switch (Tok.getKind()) { case tok::code_completion: - Actions.CodeCompleteObjCAtExpression(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCAtExpression(getCurScope()); return ExprError(); case tok::minus: @@ -3016,8 +3020,8 @@ ExprResult Parser::ParseObjCMessageExpression() { SourceLocation LBracLoc = ConsumeBracket(); // consume '[' if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCMessageReceiver(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCMessageReceiver(getCurScope()); return ExprError(); } @@ -3153,6 +3157,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, InMessageExpressionRAIIObject InMessage(*this, true); if (Tok.is(tok::code_completion)) { + cutOffParsing(); if (SuperLoc.isValid()) Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, None, false); @@ -3162,7 +3167,6 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, else Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, None, false); - cutOffParsing(); return ExprError(); } @@ -3191,6 +3195,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, /// Parse the expression after ':' if (Tok.is(tok::code_completion)) { + cutOffParsing(); if (SuperLoc.isValid()) Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, KeyIdents, @@ -3204,7 +3209,6 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, KeyIdents, /*AtArgumentExpression=*/true); - cutOffParsing(); return ExprError(); } @@ -3229,6 +3233,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, // Code completion after each argument. if (Tok.is(tok::code_completion)) { + cutOffParsing(); if (SuperLoc.isValid()) Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, KeyIdents, @@ -3241,7 +3246,6 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, KeyIdents, /*AtArgumentExpression=*/false); - cutOffParsing(); return ExprError(); } @@ -3581,8 +3585,8 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { ConsumeParen(); if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents); cutOffParsing(); + Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents); return ExprError(); } @@ -3607,8 +3611,8 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { break; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents); cutOffParsing(); + Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents); return ExprError(); } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index db7e967b15ae..18e43c3734ac 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -131,6 +131,7 @@ static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) { {OMPD_declare, OMPD_simd, OMPD_declare_simd}, {OMPD_declare, OMPD_target, OMPD_declare_target}, {OMPD_declare, OMPD_variant, OMPD_declare_variant}, + {OMPD_begin_declare, OMPD_target, OMPD_begin_declare_target}, {OMPD_begin_declare, OMPD_variant, OMPD_begin_declare_variant}, {OMPD_end_declare, OMPD_variant, OMPD_end_declare_variant}, {OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel}, @@ -441,9 +442,9 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) { ConsumeToken(); if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteInitializer(getCurScope(), OmpPrivParm); Actions.FinalizeDeclaration(OmpPrivParm); - cutOffParsing(); return; } @@ -1664,30 +1665,41 @@ parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) { return SimpleClauseData(Type, Loc, LOpen, TypeLoc, RLoc); } -Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() { - // OpenMP 4.5 syntax with list of entities. - Sema::NamedDeclSetType SameDirectiveDecls; - SmallVector<std::tuple<OMPDeclareTargetDeclAttr::MapTypeTy, SourceLocation, - NamedDecl *>, - 4> - DeclareTargetDecls; - OMPDeclareTargetDeclAttr::DevTypeTy DT = OMPDeclareTargetDeclAttr::DT_Any; +void Parser::ParseOMPDeclareTargetClauses( + Sema::DeclareTargetContextInfo &DTCI) { SourceLocation DeviceTypeLoc; + bool RequiresToOrLinkClause = false; + bool HasToOrLinkClause = false; while (Tok.isNot(tok::annot_pragma_openmp_end)) { OMPDeclareTargetDeclAttr::MapTypeTy MT = OMPDeclareTargetDeclAttr::MT_To; - if (Tok.is(tok::identifier)) { + bool HasIdentifier = Tok.is(tok::identifier); + if (HasIdentifier) { + // If we see any clause we need a to or link clause. + RequiresToOrLinkClause = true; IdentifierInfo *II = Tok.getIdentifierInfo(); StringRef ClauseName = II->getName(); bool IsDeviceTypeClause = getLangOpts().OpenMP >= 50 && getOpenMPClauseKind(ClauseName) == OMPC_device_type; - // Parse 'to|link|device_type' clauses. - if (!OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT) && - !IsDeviceTypeClause) { + + bool IsToOrLinkClause = + OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT); + assert((!IsDeviceTypeClause || !IsToOrLinkClause) && "Cannot be both!"); + + if (!IsDeviceTypeClause && DTCI.Kind == OMPD_begin_declare_target) { Diag(Tok, diag::err_omp_declare_target_unexpected_clause) - << ClauseName << (getLangOpts().OpenMP >= 50 ? 1 : 0); + << ClauseName << 0; break; } + if (!IsDeviceTypeClause && !IsToOrLinkClause) { + Diag(Tok, diag::err_omp_declare_target_unexpected_clause) + << ClauseName << (getLangOpts().OpenMP >= 50 ? 2 : 1); + break; + } + + if (IsToOrLinkClause) + HasToOrLinkClause = true; + // Parse 'device_type' clause and go to next clause if any. if (IsDeviceTypeClause) { Optional<SimpleClauseData> DevTypeData = @@ -1697,16 +1709,17 @@ Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() { // We already saw another device_type clause, diagnose it. Diag(DevTypeData.getValue().Loc, diag::warn_omp_more_one_device_type_clause); + break; } switch (static_cast<OpenMPDeviceType>(DevTypeData.getValue().Type)) { case OMPC_DEVICE_TYPE_any: - DT = OMPDeclareTargetDeclAttr::DT_Any; + DTCI.DT = OMPDeclareTargetDeclAttr::DT_Any; break; case OMPC_DEVICE_TYPE_host: - DT = OMPDeclareTargetDeclAttr::DT_Host; + DTCI.DT = OMPDeclareTargetDeclAttr::DT_Host; break; case OMPC_DEVICE_TYPE_nohost: - DT = OMPDeclareTargetDeclAttr::DT_NoHost; + DTCI.DT = OMPDeclareTargetDeclAttr::DT_NoHost; break; case OMPC_DEVICE_TYPE_unknown: llvm_unreachable("Unexpected device_type"); @@ -1717,37 +1730,47 @@ Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() { } ConsumeToken(); } - auto &&Callback = [this, MT, &DeclareTargetDecls, &SameDirectiveDecls]( - CXXScopeSpec &SS, DeclarationNameInfo NameInfo) { - NamedDecl *ND = Actions.lookupOpenMPDeclareTargetName( - getCurScope(), SS, NameInfo, SameDirectiveDecls); - if (ND) - DeclareTargetDecls.emplace_back(MT, NameInfo.getLoc(), ND); - }; - if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback, - /*AllowScopeSpecifier=*/true)) + + if (DTCI.Kind == OMPD_declare_target || HasIdentifier) { + auto &&Callback = [this, MT, &DTCI](CXXScopeSpec &SS, + DeclarationNameInfo NameInfo) { + NamedDecl *ND = + Actions.lookupOpenMPDeclareTargetName(getCurScope(), SS, NameInfo); + if (!ND) + return; + Sema::DeclareTargetContextInfo::MapInfo MI{MT, NameInfo.getLoc()}; + bool FirstMapping = DTCI.ExplicitlyMapped.try_emplace(ND, MI).second; + if (!FirstMapping) + Diag(NameInfo.getLoc(), diag::err_omp_declare_target_multiple) + << NameInfo.getName(); + }; + if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback, + /*AllowScopeSpecifier=*/true)) + break; + } + + if (Tok.is(tok::l_paren)) { + Diag(Tok, + diag::err_omp_begin_declare_target_unexpected_implicit_to_clause); + break; + } + if (!HasIdentifier && Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, + diag::err_omp_declare_target_unexpected_clause_after_implicit_to); break; + } // Consume optional ','. if (Tok.is(tok::comma)) ConsumeToken(); } + + // For declare target require at least 'to' or 'link' to be present. + if (DTCI.Kind == OMPD_declare_target && RequiresToOrLinkClause && + !HasToOrLinkClause) + Diag(DTCI.Loc, diag::err_omp_declare_target_missing_to_or_link_clause); + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); - ConsumeAnyToken(); - for (auto &MTLocDecl : DeclareTargetDecls) { - OMPDeclareTargetDeclAttr::MapTypeTy MT; - SourceLocation Loc; - NamedDecl *ND; - std::tie(MT, Loc, ND) = MTLocDecl; - // device_type clause is applied only to functions. - Actions.ActOnOpenMPDeclareTargetName( - ND, Loc, MT, isa<VarDecl>(ND) ? OMPDeclareTargetDeclAttr::DT_Any : DT); - } - SmallVector<Decl *, 4> Decls(SameDirectiveDecls.begin(), - SameDirectiveDecls.end()); - if (Decls.empty()) - return DeclGroupPtrTy(); - return Actions.BuildDeclaratorGroup(Decls); } void Parser::skipUntilPragmaOpenMPEnd(OpenMPDirectiveKind DKind) { @@ -1784,10 +1807,11 @@ void Parser::parseOMPEndDirective(OpenMPDirectiveKind BeginKind, SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); } -void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind, +void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind BeginDKind, + OpenMPDirectiveKind EndDKind, SourceLocation DKLoc) { - parseOMPEndDirective(OMPD_declare_target, OMPD_end_declare_target, DKind, - DKLoc, Tok.getLocation(), + parseOMPEndDirective(BeginDKind, OMPD_end_declare_target, EndDKind, DKLoc, + Tok.getLocation(), /* SkipUntilOpenMPEnd */ false); // Skip the last annot_pragma_openmp_end. if (Tok.is(tok::annot_pragma_openmp_end)) @@ -1833,7 +1857,8 @@ void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind, Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, bool Delayed, DeclSpec::TST TagType, Decl *Tag) { - assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) && + "Not an OpenMP directive!"); ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); @@ -1851,7 +1876,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( Toks.push_back(Tok); while (Cnt && Tok.isNot(tok::eof)) { (void)ConsumeAnyToken(); - if (Tok.is(tok::annot_pragma_openmp)) + if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp)) ++Cnt; else if (Tok.is(tok::annot_pragma_openmp_end)) --Cnt; @@ -2074,7 +2099,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( ConsumeAnyToken(); DeclGroupPtrTy Ptr; - if (Tok.is(tok::annot_pragma_openmp)) { + if (Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp)) { Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, Delayed, TagType, Tag); } else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) { @@ -2101,58 +2126,48 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( ParseOMPDeclareVariantClauses(Ptr, Toks, Loc); return Ptr; } + case OMPD_begin_declare_target: case OMPD_declare_target: { SourceLocation DTLoc = ConsumeAnyToken(); - if (Tok.isNot(tok::annot_pragma_openmp_end)) { - return ParseOMPDeclareTargetClauses(); - } + bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end); + bool HasImplicitMappings = + DKind == OMPD_begin_declare_target || !HasClauses; + Sema::DeclareTargetContextInfo DTCI(DKind, DTLoc); + if (HasClauses) + ParseOMPDeclareTargetClauses(DTCI); // Skip the last annot_pragma_openmp_end. ConsumeAnyToken(); - if (!Actions.ActOnStartOpenMPDeclareTargetDirective(DTLoc)) - return DeclGroupPtrTy(); - - ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false); - llvm::SmallVector<Decl *, 4> Decls; - DKind = parseOpenMPDirectiveKind(*this); - while (DKind != OMPD_end_declare_target && Tok.isNot(tok::eof) && - Tok.isNot(tok::r_brace)) { - DeclGroupPtrTy Ptr; - // Here we expect to see some function declaration. - if (AS == AS_none) { - assert(TagType == DeclSpec::TST_unspecified); - MaybeParseCXX11Attributes(Attrs); - ParsingDeclSpec PDS(*this); - Ptr = ParseExternalDeclaration(Attrs, &PDS); - } else { - Ptr = - ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag); - } - if (Ptr) { - DeclGroupRef Ref = Ptr.get(); - Decls.append(Ref.begin(), Ref.end()); - } - if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) { - TentativeParsingAction TPA(*this); - ConsumeAnnotationToken(); - DKind = parseOpenMPDirectiveKind(*this); - if (DKind != OMPD_end_declare_target) - TPA.Revert(); - else - TPA.Commit(); - } + if (HasImplicitMappings) { + Actions.ActOnStartOpenMPDeclareTargetContext(DTCI); + return nullptr; } - ParseOMPEndDeclareTargetDirective(DKind, DTLoc); - Actions.ActOnFinishOpenMPDeclareTargetDirective(); + Actions.ActOnFinishedOpenMPDeclareTargetContext(DTCI); + llvm::SmallVector<Decl *, 4> Decls; + for (auto &It : DTCI.ExplicitlyMapped) + Decls.push_back(It.first); return Actions.BuildDeclaratorGroup(Decls); } + case OMPD_end_declare_target: { + if (!Actions.isInOpenMPDeclareTargetContext()) { + Diag(Tok, diag::err_omp_unexpected_directive) + << 1 << getOpenMPDirectiveName(DKind); + break; + } + const Sema::DeclareTargetContextInfo &DTCI = + Actions.ActOnOpenMPEndDeclareTargetDirective(); + ParseOMPEndDeclareTargetDirective(DTCI.Kind, DKind, DTCI.Loc); + return nullptr; + } case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; case OMPD_parallel: case OMPD_simd: + case OMPD_tile: + case OMPD_unroll: case OMPD_task: case OMPD_taskyield: case OMPD_barrier: @@ -2190,7 +2205,6 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_parallel_master_taskloop: case OMPD_parallel_master_taskloop_simd: case OMPD_distribute: - case OMPD_end_declare_target: case OMPD_target_update: case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: @@ -2206,6 +2220,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: case OMPD_target_teams_distribute_simd: + case OMPD_dispatch: + case OMPD_masked: Diag(Tok, diag::err_omp_unexpected_directive) << 1 << getOpenMPDirectiveName(DKind); break; @@ -2255,12 +2271,13 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( /// simd' | 'teams distribute parallel for simd' | 'teams distribute /// parallel for' | 'target teams' | 'target teams distribute' | 'target /// teams distribute parallel for' | 'target teams distribute parallel -/// for simd' | 'target teams distribute simd' {clause} +/// for simd' | 'target teams distribute simd' | 'masked' {clause} /// annot_pragma_openmp_end /// StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { - assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) && + "Not an OpenMP directive!"); ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); SmallVector<OMPClause *, 5> Clauses; @@ -2377,6 +2394,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { case OMPD_target_enter_data: case OMPD_target_exit_data: case OMPD_target_update: + case OMPD_interop: if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == ParsedStmtContext()) { Diag(Tok, diag::err_omp_immediate_directive) @@ -2387,6 +2405,8 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { LLVM_FALLTHROUGH; case OMPD_parallel: case OMPD_simd: + case OMPD_tile: + case OMPD_unroll: case OMPD_for: case OMPD_for_simd: case OMPD_sections: @@ -2427,7 +2447,9 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { case OMPD_target_teams_distribute: case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: - case OMPD_target_teams_distribute_simd: { + case OMPD_target_teams_distribute_simd: + case OMPD_dispatch: + case OMPD_masked: { // Special processing for flush and depobj clauses. Token ImplicitTok; bool ImplicitClauseAllowed = false; @@ -2521,6 +2543,11 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { HasAssociatedStatement = false; } + if (DKind == OMPD_tile && !FirstClauses[unsigned(OMPC_sizes)].getInt()) { + Diag(Loc, diag::err_omp_required_clause) + << getOpenMPDirectiveName(OMPD_tile) << "sizes"; + } + StmtResult AssociatedStmt; if (HasAssociatedStatement) { // The body is a block scope like in Lambdas and Blocks. @@ -2529,7 +2556,15 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { // the captured region. Code elsewhere assumes that any FunctionScopeInfo // should have at least one compound statement scope within it. ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false); - AssociatedStmt = (Sema::CompoundScopeRAII(Actions), ParseStatement()); + { + Sema::CompoundScopeRAII Scope(Actions); + AssociatedStmt = ParseStatement(); + + if (AssociatedStmt.isUsable() && isOpenMPLoopDirective(DKind) && + getLangOpts().OpenMPIRBuilder) + AssociatedStmt = + Actions.ActOnOpenMPCanonicalLoop(AssociatedStmt.get()); + } AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); } else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data || DKind == OMPD_target_exit_data) { @@ -2550,6 +2585,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { } case OMPD_declare_simd: case OMPD_declare_target: + case OMPD_begin_declare_target: case OMPD_end_declare_target: case OMPD_requires: case OMPD_begin_declare_variant: @@ -2633,6 +2669,37 @@ bool Parser::ParseOpenMPSimpleVarList( return !IsCorrect; } +OMPClause *Parser::ParseOpenMPSizesClause() { + SourceLocation ClauseNameLoc = ConsumeToken(); + SmallVector<Expr *, 4> ValExprs; + + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.consumeOpen()) { + Diag(Tok, diag::err_expected) << tok::l_paren; + return nullptr; + } + + while (true) { + ExprResult Val = ParseConstantExpression(); + if (!Val.isUsable()) { + T.skipToEnd(); + return nullptr; + } + + ValExprs.push_back(Val.get()); + + if (Tok.is(tok::r_paren) || Tok.is(tok::annot_pragma_openmp_end)) + break; + + ExpectAndConsume(tok::comma); + } + + T.consumeClose(); + + return Actions.ActOnOpenMPSizesClause( + ValExprs, ClauseNameLoc, T.getOpenLocation(), T.getCloseLocation()); +} + OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) { SourceLocation Loc = Tok.getLocation(); ConsumeAnyToken(); @@ -2643,7 +2710,8 @@ OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) { return nullptr; SmallVector<Sema::UsesAllocatorsData, 4> Data; do { - ExprResult Allocator = ParseCXXIdExpression(); + ExprResult Allocator = + getLangOpts().CPlusPlus ? ParseCXXIdExpression() : ParseExpression(); if (Allocator.isInvalid()) { SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -2655,7 +2723,8 @@ OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) { BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); T.consumeOpen(); - ExprResult AllocatorTraits = ParseCXXIdExpression(); + ExprResult AllocatorTraits = + getLangOpts().CPlusPlus ? ParseCXXIdExpression() : ParseExpression(); T.consumeClose(); if (AllocatorTraits.isInvalid()) { SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, @@ -2727,6 +2796,10 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_allocator: case OMPC_depobj: case OMPC_detach: + case OMPC_novariants: + case OMPC_nocontext: + case OMPC_filter: + case OMPC_partial: // OpenMP [2.5, Restrictions] // At most one num_threads clause can appear on the directive. // OpenMP [2.8.1, simd construct, Restrictions] @@ -2749,13 +2822,17 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, // At most one allocator clause can appear on the directive. // OpenMP 5.0, 2.10.1 task Construct, Restrictions. // At most one detach clause can appear on the directive. + // OpenMP 5.1, 2.3.6 dispatch Construct, Restrictions. + // At most one novariants clause can appear on a dispatch directive. + // At most one nocontext clause can appear on a dispatch directive. if (!FirstClause) { Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0; ErrorFound = true; } - if (CKind == OMPC_ordered && PP.LookAhead(/*N=*/0).isNot(tok::l_paren)) + if ((CKind == OMPC_ordered || CKind == OMPC_partial) && + PP.LookAhead(/*N=*/0).isNot(tok::l_paren)) Clause = ParseOpenMPClause(CKind, WrongDirective); else Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective); @@ -2818,7 +2895,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_unified_shared_memory: case OMPC_reverse_offload: case OMPC_dynamic_allocators: - case OMPC_destroy: + case OMPC_full: // OpenMP [2.7.1, Restrictions, p. 9] // Only one ordered clause can appear on a loop directive. // OpenMP [2.7.1, Restrictions, C/C++, p. 4] @@ -2870,9 +2947,33 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_affinity: Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective); break; + case OMPC_sizes: + if (!FirstClause) { + Diag(Tok, diag::err_omp_more_one_clause) + << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0; + ErrorFound = true; + } + + Clause = ParseOpenMPSizesClause(); + break; case OMPC_uses_allocators: Clause = ParseOpenMPUsesAllocatorClause(DKind); break; + case OMPC_destroy: + if (DKind != OMPD_interop) { + if (!FirstClause) { + Diag(Tok, diag::err_omp_more_one_clause) + << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0; + ErrorFound = true; + } + Clause = ParseOpenMPClause(CKind, WrongDirective); + break; + } + LLVM_FALLTHROUGH; + case OMPC_init: + case OMPC_use: + Clause = ParseOpenMPInteropClause(CKind, WrongDirective); + break; case OMPC_device_type: case OMPC_unknown: skipUntilPragmaOpenMPEnd(DKind); @@ -2969,6 +3070,144 @@ OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind, return Actions.ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc, LLoc, RLoc); } +/// Parsing of OpenMP clauses that use an interop-var. +/// +/// init-clause: +/// init([interop-modifier, ]interop-type[[, interop-type] ... ]:interop-var) +/// +/// destroy-clause: +/// destroy(interop-var) +/// +/// use-clause: +/// use(interop-var) +/// +/// interop-modifier: +/// prefer_type(preference-list) +/// +/// preference-list: +/// foreign-runtime-id [, foreign-runtime-id]... +/// +/// foreign-runtime-id: +/// <string-literal> | <constant-integral-expression> +/// +/// interop-type: +/// target | targetsync +/// +OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind, + bool ParseOnly) { + SourceLocation Loc = ConsumeToken(); + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(Kind).data())) + return nullptr; + + bool IsTarget = false; + bool IsTargetSync = false; + SmallVector<Expr *, 4> Prefs; + + if (Kind == OMPC_init) { + + // Parse optional interop-modifier. + if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "prefer_type") { + ConsumeToken(); + BalancedDelimiterTracker PT(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + if (PT.expectAndConsume(diag::err_expected_lparen_after, "prefer_type")) + return nullptr; + + while (Tok.isNot(tok::r_paren)) { + SourceLocation Loc = Tok.getLocation(); + ExprResult LHS = ParseCastExpression(AnyCastExpr); + ExprResult PTExpr = Actions.CorrectDelayedTyposInExpr( + ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + PTExpr = Actions.ActOnFinishFullExpr(PTExpr.get(), Loc, + /*DiscardedValue=*/false); + if (PTExpr.isUsable()) + Prefs.push_back(PTExpr.get()); + else + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + + if (Tok.is(tok::comma)) + ConsumeToken(); + } + PT.consumeClose(); + } + + if (!Prefs.empty()) { + if (Tok.is(tok::comma)) + ConsumeToken(); + else + Diag(Tok, diag::err_omp_expected_punc_after_interop_mod); + } + + // Parse the interop-types. + bool HasError = false; + while (Tok.is(tok::identifier)) { + if (PP.getSpelling(Tok) == "target") { + // OpenMP 5.1 [2.15.1, interop Construct, Restrictions] + // Each interop-type may be specified on an action-clause at most + // once. + if (IsTarget) + Diag(Tok, diag::warn_omp_more_one_interop_type) << "target"; + IsTarget = true; + } else if (PP.getSpelling(Tok) == "targetsync") { + if (IsTargetSync) + Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync"; + IsTargetSync = true; + } else { + HasError = true; + Diag(Tok, diag::err_omp_expected_interop_type); + } + ConsumeToken(); + + if (!Tok.is(tok::comma)) + break; + ConsumeToken(); + } + if (!HasError && !IsTarget && !IsTargetSync) + Diag(Tok, diag::err_omp_expected_interop_type); + + if (Tok.is(tok::colon)) + ConsumeToken(); + else if (IsTarget || IsTargetSync) + Diag(Tok, diag::warn_pragma_expected_colon) << "interop types"; + } + + // Parse the variable. + SourceLocation VarLoc = Tok.getLocation(); + ExprResult InteropVarExpr = + Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + if (!InteropVarExpr.isUsable()) { + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } + + // Parse ')'. + SourceLocation RLoc = Tok.getLocation(); + if (!T.consumeClose()) + RLoc = T.getCloseLocation(); + + if (ParseOnly || !InteropVarExpr.isUsable() || + (Kind == OMPC_init && !IsTarget && !IsTargetSync)) + return nullptr; + + if (Kind == OMPC_init) + return Actions.ActOnOpenMPInitClause(InteropVarExpr.get(), Prefs, IsTarget, + IsTargetSync, Loc, T.getOpenLocation(), + VarLoc, RLoc); + if (Kind == OMPC_use) + return Actions.ActOnOpenMPUseClause(InteropVarExpr.get(), Loc, + T.getOpenLocation(), VarLoc, RLoc); + + if (Kind == OMPC_destroy) + return Actions.ActOnOpenMPDestroyClause(InteropVarExpr.get(), Loc, + T.getOpenLocation(), VarLoc, RLoc); + + llvm_unreachable("Unexpected interop variable clause."); +} + /// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. /// /// default-clause: diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index f9b852826775..42072fe63fc8 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -14,11 +14,13 @@ #include "clang/Basic/PragmaKinds.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/Token.h" #include "clang/Parse/LoopHint.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/Scope.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; @@ -292,6 +294,10 @@ struct PragmaMaxTokensTotalHandler : public PragmaHandler { Token &FirstToken) override; }; +void markAsReinjectedForRelexing(llvm::MutableArrayRef<clang::Token> Toks) { + for (auto &T : Toks) + T.setFlag(clang::Token::IsReinjected); +} } // end namespace void Parser::initializePragmaHandlers() { @@ -399,9 +405,11 @@ void Parser::initializePragmaHandlers() { UnrollHintHandler = std::make_unique<PragmaUnrollHintHandler>("unroll"); PP.AddPragmaHandler(UnrollHintHandler.get()); + PP.AddPragmaHandler("GCC", UnrollHintHandler.get()); NoUnrollHintHandler = std::make_unique<PragmaUnrollHintHandler>("nounroll"); PP.AddPragmaHandler(NoUnrollHintHandler.get()); + PP.AddPragmaHandler("GCC", NoUnrollHintHandler.get()); UnrollAndJamHintHandler = std::make_unique<PragmaUnrollHintHandler>("unroll_and_jam"); @@ -517,9 +525,11 @@ void Parser::resetPragmaHandlers() { LoopHintHandler.reset(); PP.RemovePragmaHandler(UnrollHintHandler.get()); + PP.RemovePragmaHandler("GCC", UnrollHintHandler.get()); UnrollHintHandler.reset(); PP.RemovePragmaHandler(NoUnrollHintHandler.get()); + PP.RemovePragmaHandler("GCC", NoUnrollHintHandler.get()); NoUnrollHintHandler.reset(); PP.RemovePragmaHandler(UnrollAndJamHintHandler.get()); @@ -771,22 +781,21 @@ void Parser::HandlePragmaOpenCLExtension() { // overriding all previously issued extension directives, but only if the // behavior is set to disable." if (Name == "all") { - if (State == Disable) { + if (State == Disable) Opt.disableAll(); - Opt.enableSupportedCore(getLangOpts()); - } else { + else PP.Diag(NameLoc, diag::warn_pragma_expected_predicate) << 1; - } } else if (State == Begin) { if (!Opt.isKnown(Name) || !Opt.isSupported(Name, getLangOpts())) { Opt.support(Name); + // FIXME: Default behavior of the extension pragma is not defined. + // Therefore, it should never be added by default. + Opt.acceptsPragma(Name); } - Actions.setCurrentOpenCLExtension(Name); } else if (State == End) { - if (Name != Actions.getCurrentOpenCLExtension()) - PP.Diag(NameLoc, diag::warn_pragma_begin_end_mismatch); - Actions.setCurrentOpenCLExtension(""); - } else if (!Opt.isKnown(Name)) + // There is no behavior for this directive. We only accept this for + // backward compatibility. + } else if (!Opt.isKnown(Name) || !Opt.isWithPragma(Name)) PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << Ident; else if (Opt.isSupportedExtension(Name, getLangOpts())) Opt.enable(Name, State == Enable); @@ -2618,6 +2627,7 @@ void PragmaMSPragma::HandlePragma(Preprocessor &PP, TokenVector.push_back(EoF); // We must allocate this array with new because EnterTokenStream is going to // delete it later. + markAsReinjectedForRelexing(TokenVector); auto TokenArray = std::make_unique<Token[]>(TokenVector.size()); std::copy(TokenVector.begin(), TokenVector.end(), TokenArray.get()); auto Value = new (PP.getPreprocessorAllocator()) @@ -3175,6 +3185,7 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName, EOFTok.setLocation(Tok.getLocation()); ValueList.push_back(EOFTok); // Terminates expression for parsing. + markAsReinjectedForRelexing(ValueList); Info.Toks = llvm::makeArrayRef(ValueList).copy(PP.getPreprocessorAllocator()); Info.PragmaName = PragmaName; @@ -3631,6 +3642,7 @@ void PragmaAttributeHandler::HandlePragma(Preprocessor &PP, EOFTok.setLocation(EndLoc); AttributeTokens.push_back(EOFTok); + markAsReinjectedForRelexing(AttributeTokens); Info->Tokens = llvm::makeArrayRef(AttributeTokens).copy(PP.getPreprocessorAllocator()); } diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 26a02575010c..ebfe048513b1 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -20,6 +20,8 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/Sema/TypoCorrection.h" +#include "llvm/ADT/STLExtras.h" + using namespace clang; //===----------------------------------------------------------------------===// @@ -98,10 +100,15 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, ParenBraceBracketBalancer BalancerRAIIObj(*this); + // Because we're parsing either a statement or a declaration, the order of + // attribute parsing is important. [[]] attributes at the start of a + // statement are different from [[]] attributes that follow an __attribute__ + // at the start of the statement. Thus, we're not using MaybeParseAttributes + // here because we don't want to allow arbitrary orderings. ParsedAttributesWithRange Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true); - if (!MaybeParseOpenCLUnrollHintAttribute(Attrs)) - return StmtError(); + if (getLangOpts().OpenCL) + MaybeParseGNUAttributes(Attrs); StmtResult Res = ParseStatementOrDeclarationAfterAttributes( Stmts, StmtCtx, TrailingElseLoc, Attrs); @@ -113,7 +120,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, if (Attrs.empty() || Res.isInvalid()) return Res; - return Actions.ProcessStmtAttributes(Res.get(), Attrs, Attrs.Range); + return Actions.ActOnAttributedStmt(Attrs, Res.get()); } namespace { @@ -165,14 +172,13 @@ Retry: switch (Kind) { case tok::at: // May be a @try or @throw statement { - ProhibitAttributes(Attrs); // TODO: is it correct? AtLoc = ConsumeToken(); // consume @ return ParseObjCAtStatement(AtLoc, StmtCtx); } case tok::code_completion: - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement); cutOffParsing(); + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement); return StmtError(); case tok::identifier: { @@ -210,7 +216,11 @@ Retry: if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != ParsedStmtContext()) && - (GNUAttributeLoc.isValid() || isDeclarationStatement())) { + ((GNUAttributeLoc.isValid() && + !(!Attrs.empty() && + llvm::all_of( + Attrs, [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }))) || + isDeclarationStatement())) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl; if (GNUAttributeLoc.isValid()) { @@ -391,7 +401,12 @@ Retry: return HandlePragmaCaptured(); case tok::annot_pragma_openmp: + // Prohibit attributes that are not OpenMP attributes, but only before + // processing a #pragma omp clause. ProhibitAttributes(Attrs); + LLVM_FALLTHROUGH; + case tok::annot_attr_openmp: + // Do not prohibit attributes if they were OpenMP attributes. return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx); case tok::annot_pragma_ms_pointers_to_members: @@ -638,19 +653,12 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs, // attributes as part of a statement in that case). That looks like a bug. if (!getLangOpts().CPlusPlus || Tok.is(tok::semi)) attrs.takeAllFrom(TempAttrs); - else if (isDeclarationStatement()) { + else { StmtVector Stmts; - // FIXME: We should do this whether or not we have a declaration - // 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, StmtCtx, nullptr, TempAttrs); if (!TempAttrs.empty() && !SubStmt.isInvalid()) - SubStmt = Actions.ProcessStmtAttributes(SubStmt.get(), TempAttrs, - TempAttrs.Range); - } else { - Diag(Tok, diag::err_expected_after) << "__attribute__" << tok::semi; + SubStmt = Actions.ActOnAttributedStmt(TempAttrs, SubStmt.get()); } } @@ -715,8 +723,8 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx, ColonLoc = SourceLocation(); if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteCase(getCurScope()); cutOffParsing(); + Actions.CodeCompleteCase(getCurScope()); return StmtError(); } @@ -1134,7 +1142,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); R = handleExprStmt(Res, SubStmtCtx); if (R.isUsable()) - R = Actions.ProcessStmtAttributes(R.get(), attrs, attrs.Range); + R = Actions.ActOnAttributedStmt(attrs, R.get()); } } @@ -1461,8 +1469,8 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { // Pop the 'else' scope if needed. InnerScope.Exit(); } else if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteAfterIf(getCurScope(), IsBracedThen); cutOffParsing(); + Actions.CodeCompleteAfterIf(getCurScope(), IsBracedThen); return StmtError(); } else if (InnerStatementTrailingElseLoc.isValid()) { Diag(InnerStatementTrailingElseLoc, diag::warn_dangling_else); @@ -1816,10 +1824,10 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { FullExprArg ThirdPart(Actions); if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteOrdinaryName(getCurScope(), C99orCXXorObjC? Sema::PCC_ForInit : Sema::PCC_Expression); - cutOffParsing(); return StmtError(); } @@ -1887,8 +1895,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { ConsumeToken(); // consume 'in' if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCForCollection(getCurScope(), DG); cutOffParsing(); + Actions.CodeCompleteObjCForCollection(getCurScope(), DG); return StmtError(); } Collection = ParseExpression(); @@ -1923,8 +1931,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { ConsumeToken(); // consume 'in' if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCForCollection(getCurScope(), nullptr); cutOffParsing(); + Actions.CodeCompleteObjCForCollection(getCurScope(), nullptr); return StmtError(); } Collection = ParseExpression(); @@ -1948,7 +1956,6 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { } // Parse the second part of the for specifier. - getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope); if (!ForEach && !ForRangeInfo.ParsedForRangeDecl() && !SecondPart.isInvalid()) { // Parse the second part of the for specifier. @@ -1964,7 +1971,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); SecondPart = ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean, - MightBeForRangeStmt ? &ForRangeInfo : nullptr); + MightBeForRangeStmt ? &ForRangeInfo : nullptr, + /*EnterForConditionScope*/ true); if (ForRangeInfo.ParsedForRangeDecl()) { Diag(FirstPart.get() ? FirstPart.get()->getBeginLoc() @@ -1981,6 +1989,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { } } } else { + // We permit 'continue' and 'break' in the condition of a for loop. + getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope); + ExprResult SecondExpr = ParseExpression(); if (SecondExpr.isInvalid()) SecondPart = Sema::ConditionError(); @@ -1992,6 +2003,11 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { } } + // Enter a break / continue scope, if we didn't already enter one while + // parsing the second part. + if (!(getCurScope()->getFlags() & Scope::ContinueScope)) + getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope); + // Parse the third part of the for statement. if (!ForEach && !ForRangeInfo.ParsedForRangeDecl()) { if (Tok.isNot(tok::semi)) { @@ -2177,9 +2193,9 @@ StmtResult Parser::ParseReturnStatement() { PreferredType.enterReturn(Actions, Tok.getLocation()); // FIXME: Code completion for co_return. if (Tok.is(tok::code_completion) && !IsCoreturn) { + cutOffParsing(); Actions.CodeCompleteExpression(getCurScope(), PreferredType.get(Tok.getLocation())); - cutOffParsing(); return StmtError(); } @@ -2548,19 +2564,3 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { } Braces.consumeClose(); } - -bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) { - MaybeParseGNUAttributes(Attrs); - - if (Attrs.empty()) - return true; - - if (Attrs.begin()->getKind() != ParsedAttr::AT_OpenCLUnrollHint) - return true; - - if (!(Tok.is(tok::kw_for) || Tok.is(tok::kw_while) || Tok.is(tok::kw_do))) { - Diag(Tok, diag::err_opencl_unroll_hint_on_non_loop); - return false; - } - return true; -} diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp index bdf40c291cb6..e520151dcad7 100644 --- a/clang/lib/Parse/ParseStmtAsm.cpp +++ b/clang/lib/Parse/ParseStmtAsm.cpp @@ -577,19 +577,22 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { TheTarget->createMCAsmInfo(*MRI, TT, MCOptions)); // Get the instruction descriptor. std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo()); - std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); std::unique_ptr<llvm::MCSubtargetInfo> STI( TheTarget->createMCSubtargetInfo(TT, TO.CPU, FeaturesStr)); // Target MCTargetDesc may not be linked in clang-based tools. - if (!MAI || !MII || !MOFI || !STI) { + + if (!MAI || !MII || !STI) { Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << "target MC unavailable"; return EmptyStmt(); } llvm::SourceMgr TempSrcMgr; - llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr); - MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, Ctx); + llvm::MCContext Ctx(TheTriple, MAI.get(), MRI.get(), STI.get(), &TempSrcMgr); + std::unique_ptr<llvm::MCObjectFileInfo> MOFI( + TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false)); + Ctx.setObjectFileInfo(MOFI.get()); + std::unique_ptr<llvm::MemoryBuffer> Buffer = llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>"); @@ -630,9 +633,9 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { SmallVector<std::pair<void *, bool>, 4> OpExprs; SmallVector<std::string, 4> Constraints; SmallVector<std::string, 4> Clobbers; - if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, NumOutputs, - NumInputs, OpExprs, Constraints, Clobbers, - MII.get(), IP.get(), Callback)) + if (Parser->parseMSInlineAsm(AsmStringIR, NumOutputs, NumInputs, OpExprs, + Constraints, Clobbers, MII.get(), IP.get(), + Callback)) return StmtError(); // Filter out "fpsw" and "mxcsr". They aren't valid GCC asm clobber diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 3bf2bc455bfe..c0bfbbde40ac 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -353,8 +353,8 @@ struct Parser::ConditionDeclarationOrInitStatementState { if (CanBeForRangeDecl) { // Skip until we hit a ')', ';', or a ':' with no matching '?'. // The final case is a for range declaration, the rest are not. + unsigned QuestionColonDepth = 0; while (true) { - unsigned QuestionColonDepth = 0; P.SkipUntil({tok::r_paren, tok::semi, tok::question, tok::colon}, StopBeforeMatch); if (P.Tok.is(tok::question)) diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 9b0f921b4269..c81dd03ffaaa 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -49,10 +49,10 @@ IdentifierInfo *Parser::getSEHExceptKeyword() { } Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) - : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), - GreaterThanIsOperator(true), ColonIsSacred(false), - InMessageExpression(false), TemplateParameterDepth(0), - ParsingInObjCContainer(false) { + : PP(pp), PreferredType(pp.isCodeCompletionEnabled()), Actions(actions), + Diags(PP.getDiagnostics()), GreaterThanIsOperator(true), + ColonIsSacred(false), InMessageExpression(false), + TemplateParameterDepth(0), ParsingInObjCContainer(false) { SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies; Tok.startToken(); Tok.setKind(tok::eof); @@ -309,6 +309,7 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) { return false; case tok::annot_pragma_openmp: + case tok::annot_attr_openmp: case tok::annot_pragma_openmp_end: // Stop before an OpenMP pragma boundary. if (OpenMPDirectiveParsing) @@ -494,6 +495,7 @@ void Parser::Initialize() { Ident_instancetype = nullptr; Ident_final = nullptr; Ident_sealed = nullptr; + Ident_abstract = nullptr; Ident_override = nullptr; Ident_GNU_final = nullptr; Ident_import = nullptr; @@ -503,10 +505,12 @@ void Parser::Initialize() { Ident_vector = nullptr; Ident_bool = nullptr; + Ident_Bool = nullptr; Ident_pixel = nullptr; if (getLangOpts().AltiVec || getLangOpts().ZVector) { Ident_vector = &PP.getIdentifierTable().get("vector"); Ident_bool = &PP.getIdentifierTable().get("bool"); + Ident_Bool = &PP.getIdentifierTable().get("_Bool"); } if (getLangOpts().AltiVec) Ident_pixel = &PP.getIdentifierTable().get("pixel"); @@ -795,6 +799,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::annot_pragma_opencl_extension: HandlePragmaOpenCLExtension(); return nullptr; + case tok::annot_attr_openmp: case tok::annot_pragma_openmp: { AccessSpecifier AS = AS_none; return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs); @@ -870,6 +875,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, SingleDecl = ParseObjCMethodDefinition(); break; case tok::code_completion: + cutOffParsing(); if (CurParsedObjCImpl) { // Code-complete Objective-C methods even without leading '-'/'+' prefix. Actions.CodeCompleteObjCMethodDecl(getCurScope(), @@ -879,7 +885,6 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, Actions.CodeCompleteOrdinaryName( getCurScope(), CurParsedObjCImpl ? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace); - cutOffParsing(); return nullptr; case tok::kw_import: SingleDecl = ParseModuleImport(SourceLocation()); @@ -1079,8 +1084,6 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, DS, AnonRecord); DS.complete(TheDecl); - if (getLangOpts().OpenCL) - Actions.setCurrentOpenCLExtensionForDecl(TheDecl); if (AnonRecord) { Decl* decls[] = {AnonRecord, TheDecl}; return Actions.BuildDeclaratorGroup(decls); @@ -1213,7 +1216,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // a definition. Late parsed attributes are checked at the end. if (Tok.isNot(tok::equal)) { for (const ParsedAttr &AL : D.getAttributes()) - if (AL.isKnownToGCC() && !AL.isCXX11Attribute()) + if (AL.isKnownToGCC() && !AL.isStandardAttributeSyntax()) Diag(AL.getLoc(), diag::warn_attribute_on_function_definition) << AL; } @@ -1695,6 +1698,11 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) { break; case Sema::NC_Type: { + if (TryAltiVecVectorToken()) + // vector has been found as a type id when altivec is enabled but + // this is followed by a declaration specifier so this is really the + // altivec vector token. Leave it unannotated. + break; SourceLocation BeginLoc = NameLoc; if (SS.isNotEmpty()) BeginLoc = SS.getBeginLoc(); @@ -1736,6 +1744,11 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) { return ANK_Success; case Sema::NC_NonType: + if (TryAltiVecVectorToken()) + // vector has been found as a non-type id when altivec is enabled but + // this is followed by a declaration specifier so this is really the + // altivec vector token. Leave it unannotated. + break; Tok.setKind(tok::annot_non_type); setNonTypeAnnotation(Tok, Classification.getNonTypeDecl()); Tok.setLocation(NameLoc); @@ -2114,21 +2127,21 @@ SourceLocation Parser::handleUnexpectedCodeCompletionToken() { for (Scope *S = getCurScope(); S; S = S->getParent()) { if (S->getFlags() & Scope::FnScope) { + cutOffParsing(); Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_RecoveryInFunction); - cutOffParsing(); return PrevTokLocation; } if (S->getFlags() & Scope::ClassScope) { - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class); cutOffParsing(); + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class); return PrevTokLocation; } } - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace); cutOffParsing(); + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace); return PrevTokLocation; } @@ -2452,8 +2465,8 @@ bool Parser::ParseModuleName( while (true) { if (!Tok.is(tok::identifier)) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteModuleImport(UseLoc, Path); cutOffParsing(); + Actions.CodeCompleteModuleImport(UseLoc, Path); return true; } |