diff options
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/Makefile | 18 | ||||
-rw-r--r-- | lib/Parse/ParseAST.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 31 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 249 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 189 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 179 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 215 | ||||
-rw-r--r-- | lib/Parse/ParseInit.cpp | 18 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 201 | ||||
-rw-r--r-- | lib/Parse/ParseOpenMP.cpp | 1133 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.cpp | 275 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 192 | ||||
-rw-r--r-- | lib/Parse/ParseStmtAsm.cpp | 82 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 73 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 193 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 133 |
16 files changed, 2248 insertions, 934 deletions
diff --git a/lib/Parse/Makefile b/lib/Parse/Makefile deleted file mode 100644 index 5ec7c333c504..000000000000 --- a/lib/Parse/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- clang/lib/Parse/Makefile ----------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements the Parser library for the C-Language front-end. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../.. -LIBRARYNAME := clangParse - -include $(CLANG_LEVEL)/Makefile - diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp index ccf947984945..1fb57a08c433 100644 --- a/lib/Parse/ParseAST.cpp +++ b/lib/Parse/ParseAST.cpp @@ -19,7 +19,6 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Sema/CodeCompleteConsumer.h" -#include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaConsumer.h" #include "llvm/Support/CrashRecoveryContext.h" diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index e536644d5bf6..39fcc8270419 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -52,7 +52,8 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, } } - HandleMemberFunctionDeclDelays(D, FnD); + if (FnD) + HandleMemberFunctionDeclDelays(D, FnD); D.complete(FnD); @@ -100,6 +101,12 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, return FnD; } + if (SkipFunctionBodies && (!FnD || Actions.canSkipFunctionBody(FnD)) && + trySkippingFunctionBody()) { + Actions.ActOnSkippedFunctionBody(FnD); + return FnD; + } + // In delayed template parsing mode, if we are within a class template // or if we are about to parse function member template then consume // the tokens and store them for parsing at the end of the translation unit. @@ -325,7 +332,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // Parse the default argument from its saved token stream. Toks->push_back(Tok); // So that the current token doesn't get lost - PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false); + PP.EnterTokenStream(*Toks, true); // Consume the previously-pushed token. ConsumeAnyToken(); @@ -380,7 +387,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { assert (!OldParam->hasUnparsedDefaultArg()); if (OldParam->hasUninstantiatedDefaultArg()) Param->setUninstantiatedDefaultArg( - Param->getUninstantiatedDefaultArg()); + OldParam->getUninstantiatedDefaultArg()); else Param->setDefaultArg(OldParam->getInit()); } @@ -399,7 +406,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // Parse the default argument from its saved token stream. Toks->push_back(Tok); // So that the current token doesn't get lost - PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false); + PP.EnterTokenStream(*Toks, true); // Consume the previously-pushed token. ConsumeAnyToken(); @@ -504,7 +511,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { // Append the current token at the end of the new token stream so that it // doesn't get lost. LM.Toks.push_back(Tok); - PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); + PP.EnterTokenStream(LM.Toks, true); // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); @@ -563,8 +570,10 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { if (Tok.is(tok::eof) && Tok.getEofData() == LM.D) ConsumeAnyToken(); - if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(LM.D)) - Actions.ActOnFinishInlineMethodDef(MD); + if (auto *FD = dyn_cast_or_null<FunctionDecl>(LM.D)) + if (isa<CXXMethodDecl>(FD) || + FD->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend)) + Actions.ActOnFinishInlineFunctionDef(FD); } /// ParseLexedMemberInitializers - We finished parsing the member specification @@ -617,7 +626,7 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { // Append the current token at the end of the new token stream so that it // doesn't get lost. MI.Toks.push_back(Tok); - PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false); + PP.EnterTokenStream(MI.Toks, true); // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); @@ -971,10 +980,10 @@ public: // Put back the original tokens. Self.SkipUntil(EndKind, StopAtSemi | StopBeforeMatch); if (Toks.size()) { - Token *Buffer = new Token[Toks.size()]; - std::copy(Toks.begin() + 1, Toks.end(), Buffer); + auto Buffer = llvm::make_unique<Token[]>(Toks.size()); + std::copy(Toks.begin() + 1, Toks.end(), Buffer.get()); Buffer[Toks.size() - 1] = Self.Tok; - Self.PP.EnterTokenStream(Buffer, Toks.size(), true, /*Owned*/true); + Self.PP.EnterTokenStream(std::move(Buffer), Toks.size(), true); Self.Tok = Toks.front(); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index c64b97d01b9a..45e1c3e465ce 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -28,6 +28,7 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ScopedPrinter.h" using namespace clang; @@ -609,7 +610,6 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { case tok::kw___ptr64: case tok::kw___w64: case tok::kw___ptr32: - case tok::kw___unaligned: case tok::kw___sptr: case tok::kw___uptr: { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); @@ -670,7 +670,7 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { } } -void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) { +void Parser::ParseOpenCLKernelAttributes(ParsedAttributes &attrs) { // Treat these like attributes while (Tok.is(tok::kw___kernel)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); @@ -720,7 +720,7 @@ static bool VersionNumberSeparator(const char Separator) { /// simple-integer ',' simple-integer /// simple-integer ',' simple-integer ',' simple-integer VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { - Range = Tok.getLocation(); + Range = SourceRange(Tok.getLocation(), Tok.getEndLoc()); if (!Tok.is(tok::numeric_constant)) { Diag(Tok, diag::err_expected_version); @@ -833,11 +833,15 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { /// \brief Parse the contents of the "availability" attribute. /// /// availability-attribute: -/// 'availability' '(' platform ',' version-arg-list, opt-message')' +/// 'availability' '(' platform ',' opt-strict version-arg-list, +/// opt-replacement, opt-message')' /// /// platform: /// identifier /// +/// opt-strict: +/// 'strict' ',' +/// /// version-arg-list: /// version-arg /// version-arg ',' version-arg-list @@ -847,6 +851,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { /// 'deprecated' '=' version /// 'obsoleted' = version /// 'unavailable' +/// opt-replacement: +/// 'replacement' '=' <string> /// opt-message: /// 'message' '=' <string> void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, @@ -858,7 +864,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, AttributeList::Syntax Syntax) { enum { Introduced, Deprecated, Obsoleted, Unknown }; AvailabilityChange Changes[Unknown]; - ExprResult MessageExpr; + ExprResult MessageExpr, ReplacementExpr; // Opening '('. BalancedDelimiterTracker T(*this, tok::l_paren); @@ -867,13 +873,20 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, return; } - // Parse the platform name, + // Parse the platform name. if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_availability_expected_platform); SkipUntil(tok::r_paren, StopAtSemi); return; } IdentifierLoc *Platform = ParseIdentifierLoc(); + // Canonicalize platform name from "macosx" to "macos". + if (Platform->Ident && Platform->Ident->getName() == "macosx") + Platform->Ident = PP.getIdentifierInfo("macos"); + // Canonicalize platform name from "macosx_app_extension" to + // "macos_app_extension". + if (Platform->Ident && Platform->Ident->getName() == "macosx_app_extension") + Platform->Ident = PP.getIdentifierInfo("macos_app_extension"); // Parse the ',' following the platform name. if (ExpectAndConsume(tok::comma)) { @@ -889,10 +902,13 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, Ident_obsoleted = PP.getIdentifierInfo("obsoleted"); Ident_unavailable = PP.getIdentifierInfo("unavailable"); Ident_message = PP.getIdentifierInfo("message"); + Ident_strict = PP.getIdentifierInfo("strict"); + Ident_replacement = PP.getIdentifierInfo("replacement"); } - // Parse the set of introductions/deprecations/removals. - SourceLocation UnavailableLoc; + // Parse the optional "strict", the optional "replacement" and the set of + // introductions/deprecations/removals. + SourceLocation UnavailableLoc, StrictLoc; do { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_availability_expected_change); @@ -902,6 +918,15 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, IdentifierInfo *Keyword = Tok.getIdentifierInfo(); SourceLocation KeywordLoc = ConsumeToken(); + if (Keyword == Ident_strict) { + if (StrictLoc.isValid()) { + Diag(KeywordLoc, diag::err_availability_redundant) + << Keyword << SourceRange(StrictLoc); + } + StrictLoc = KeywordLoc; + continue; + } + if (Keyword == Ident_unavailable) { if (UnavailableLoc.isValid()) { Diag(KeywordLoc, diag::err_availability_redundant) @@ -917,14 +942,17 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, return; } ConsumeToken(); - if (Keyword == Ident_message) { + if (Keyword == Ident_message || Keyword == Ident_replacement) { if (Tok.isNot(tok::string_literal)) { Diag(Tok, diag::err_expected_string_literal) << /*Source='availability attribute'*/2; SkipUntil(tok::r_paren, StopAtSemi); return; } - MessageExpr = ParseStringLiteralExpression(); + if (Keyword == Ident_message) + MessageExpr = ParseStringLiteralExpression(); + else + ReplacementExpr = ParseStringLiteralExpression(); // Also reject wide string literals. if (StringLiteral *MessageStringLiteral = cast_or_null<StringLiteral>(MessageExpr.get())) { @@ -936,7 +964,10 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, return; } } - break; + if (Keyword == Ident_message) + break; + else + continue; } // Special handling of 'NA' only when applied to introduced or @@ -1023,7 +1054,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, Changes[Deprecated], Changes[Obsoleted], UnavailableLoc, MessageExpr.get(), - Syntax); + Syntax, StrictLoc, ReplacementExpr.get()); } /// \brief Parse the contents of the "objc_bridge_related" attribute. @@ -1187,7 +1218,7 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, // Append the current token at the end of the new token stream so that it // doesn't get lost. LA.Toks.push_back(Tok); - PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false); + PP.EnterTokenStream(LA.Toks, true); // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); @@ -1402,8 +1433,8 @@ void Parser::handleDeclspecAlignBeforeClassKey(ParsedAttributesWithRange &Attrs, while (AL) { AttributeList *Next = AL->getNext(); - // We only consider attributes using the appropriate '__declspec' spelling, - // this behavior doesn't extend to any other spellings. + // We only consider attributes using the appropriate '__declspec' spelling. + // This behavior doesn't extend to any other spellings. if (AL->getKind() == AttributeList::AT_Aligned && AL->isDeclspecAttribute()) { // Stitch the attribute into the tag's attribute list. @@ -1522,7 +1553,7 @@ Parser::ParseSimpleDeclaration(unsigned Context, // may get this far before the problem becomes obvious. if (DS.hasTagDefinition() && DiagnoseMissingSemiAfterTagDefinition(DS, AS_none, DSContext)) - return DeclGroupPtrTy(); + return nullptr; // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' @@ -1530,9 +1561,14 @@ Parser::ParseSimpleDeclaration(unsigned Context, ProhibitAttributes(Attrs); DeclEnd = Tok.getLocation(); if (RequireSemi) ConsumeToken(); + RecordDecl *AnonRecord = nullptr; Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, - DS); + DS, AnonRecord); DS.complete(TheDecl); + if (AnonRecord) { + Decl* decls[] = {AnonRecord, TheDecl}; + return Actions.BuildDeclaratorGroup(decls, /*TypeMayContainAuto=*/false); + } return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -1701,7 +1737,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // Bail out if the first declarator didn't seem well-formed. if (!D.hasName() && !D.mayOmitIdentifier()) { SkipMalformedDecl(); - return DeclGroupPtrTy(); + return nullptr; } // Save late-parsed attributes for now; they need to be parsed in the @@ -1766,19 +1802,19 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } else { Diag(Tok, diag::err_expected_fn_body); SkipUntil(tok::semi); - return DeclGroupPtrTy(); + return nullptr; } } else { if (Tok.is(tok::l_brace)) { Diag(Tok, diag::err_function_definition_not_allowed); SkipMalformedDecl(); - return DeclGroupPtrTy(); + return nullptr; } } } if (ParseAsmAttributesAfterDeclarator(D)) - return DeclGroupPtrTy(); + return nullptr; // C++0x [stmt.iter]p1: Check if we have a for-range-declarator. If so, we // must parse and analyze the for-range-initializer before the declaration is @@ -1975,7 +2011,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( TemplateParameterLists FakedParamLists; FakedParamLists.push_back(Actions.ActOnTemplateParameterList( 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, None, - LAngleLoc)); + LAngleLoc, nullptr)); ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D); @@ -2039,7 +2075,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( if (Init.isInvalid()) { SmallVector<tok::TokenKind, 2> StopTokens; StopTokens.push_back(tok::comma); - if (D.getContext() == Declarator::ForContext) + if (D.getContext() == Declarator::ForContext || + D.getContext() == Declarator::InitStmtContext) StopTokens.push_back(tok::r_paren); SkipUntil(StopTokens, StopAtSemi | StopBeforeMatch); Actions.ActOnInitializerError(ThisDecl); @@ -2250,6 +2287,24 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, return false; } + if (getLangOpts().CPlusPlus && (!SS || SS->isEmpty()) && + getLangOpts().MSVCCompat) { + // Lookup of an unqualified type name has failed in MSVC compatibility mode. + // Give Sema a chance to recover if we are in a template with dependent base + // classes. + if (ParsedType T = Actions.ActOnMSVCUnknownTypeName( + *Tok.getIdentifierInfo(), Tok.getLocation(), + DSC == DSC_template_type_arg)) { + const char *PrevSpec; + unsigned DiagID; + DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T, + Actions.getASTContext().getPrintingPolicy()); + DS.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); + return false; + } + } + // Otherwise, if we don't consume this token, we are going to emit an // error anyway. Try to recover from various common problems. Check // to see if this was a reference to a tag name without a tag specified. @@ -2632,7 +2687,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, bool AttrsLastTime = false; ParsedAttributesWithRange attrs(AttrFactory); // We use Sema's policy to get bool macros right. - const PrintingPolicy &Policy = Actions.getPrintingPolicy(); + PrintingPolicy Policy = Actions.getPrintingPolicy(); while (1) { bool isInvalid = false; bool isStorageClass = false; @@ -2835,12 +2890,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, << Next.getIdentifierInfo() << 1 /* type */; } - ParsedType TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(), - Next.getLocation(), - getCurScope(), &SS, - false, false, ParsedType(), - /*IsCtorOrDtorName=*/false, - /*NonTrivialSourceInfo=*/true); + ParsedType TypeRep = + Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(), + getCurScope(), &SS, false, false, nullptr, + /*IsCtorOrDtorName=*/false, + /*NonTrivialSourceInfo=*/true); // If the referenced identifier is not a type, then this declspec is // erroneous: We already checked about that it has no type specifier, and @@ -2958,16 +3012,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope()); - // MSVC: If we weren't able to parse a default template argument, and it's - // just a simple identifier, create a DependentNameType. This will allow - // us to defer the name lookup to template instantiation time, as long we - // forge a NestedNameSpecifier for the current context. - if (!TypeRep && DSContext == DSC_template_type_arg && - getLangOpts().MSVCCompat && getCurScope()->isTemplateParamScope()) { - TypeRep = Actions.ActOnDelayedDefaultTemplateArg( - *Tok.getIdentifierInfo(), Tok.getLocation()); - } - // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. if (!TypeRep) { @@ -3059,6 +3103,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, break; } + case tok::kw___unaligned: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_unaligned, Loc, PrevSpec, DiagID, + getLangOpts()); + break; + case tok::kw___sptr: case tok::kw___uptr: case tok::kw___ptr64: @@ -3069,7 +3118,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___fastcall: case tok::kw___thiscall: case tok::kw___vectorcall: - case tok::kw___unaligned: ParseMicrosoftTypeAttributes(DS.getAttributes()); continue; @@ -3080,7 +3128,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // OpenCL single token adornments. case tok::kw___kernel: - ParseOpenCLAttributes(DS.getAttributes()); + ParseOpenCLKernelAttributes(DS.getAttributes()); continue; // Nullability type specifiers. @@ -3278,6 +3326,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID, Policy); break; + case tok::kw___float128: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec, + DiagID, Policy); + break; case tok::kw_wchar_t: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID, Policy); @@ -3335,6 +3387,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } 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; +#include "clang/Basic/OpenCLImageTypes.def" case tok::kw___unknown_anytype: isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc, PrevSpec, DiagID, Policy); @@ -3403,6 +3461,22 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParseDecltypeSpecifier(DS); continue; + case tok::annot_pragma_pack: + HandlePragmaPack(); + continue; + + case tok::annot_pragma_ms_pragma: + HandlePragmaMSPragma(); + continue; + + case tok::annot_pragma_ms_vtordisp: + HandlePragmaMSVtorDisp(); + continue; + + case tok::annot_pragma_ms_pointers_to_members: + HandlePragmaMSPointersToMembers(); + continue; + case tok::kw___underlying_type: ParseUnderlyingTypeSpecifier(DS); continue; @@ -3473,9 +3547,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DiagID == diag::ext_duplicate_declspec) Diag(Tok, DiagID) << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); - else if (DiagID == diag::err_opencl_unknown_type_specifier) - Diag(Tok, DiagID) << PrevSpec << isStorageClass; - else + else if (DiagID == diag::err_opencl_unknown_type_specifier) { + const int OpenCLVer = getLangOpts().OpenCLVersion; + std::string VerSpec = llvm::to_string(OpenCLVer / 100) + + std::string (".") + + llvm::to_string((OpenCLVer % 100) / 10); + Diag(Tok, DiagID) << VerSpec << PrevSpec << isStorageClass; + } else Diag(Tok, DiagID) << PrevSpec; } @@ -3521,8 +3599,10 @@ void Parser::ParseStructDeclaration( // If there are no declarators, this is a free-standing declaration // specifier. Let the actions module cope with it. if (Tok.is(tok::semi)) { + RecordDecl *AnonRecord = nullptr; Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, - DS); + DS, AnonRecord); + assert(!AnonRecord && "Did not expect anonymous struct or union here"); DS.complete(TheDecl); return; } @@ -3625,12 +3705,12 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, if (Tok.is(tok::annot_pragma_openmp)) { // Result can be ignored, because it must be always empty. - auto Res = ParseOpenMPDeclarativeDirective(); - assert(!Res); - // Silence possible warnings. - (void)Res; + AccessSpecifier AS = AS_none; + ParsedAttributesWithRange Attrs(AttrFactory); + (void)ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs); continue; } + if (!Tok.is(tok::at)) { auto CFieldCallback = [&](ParsingFieldDeclarator &FD) { // Install the declarator into the current TagDecl. @@ -3693,8 +3773,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, T.getOpenLocation(), T.getCloseLocation(), attrs.getList()); StructScope.Exit(); - Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, - T.getCloseLocation()); + Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, T.getRange()); } /// ParseEnumSpecifier @@ -3788,7 +3867,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType); CXXScopeSpec Spec; - if (ParseOptionalCXXScopeSpecifier(Spec, ParsedType(), + if (ParseOptionalCXXScopeSpecifier(Spec, nullptr, /*EnteringContext=*/true)) return; @@ -4189,7 +4268,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); - Actions.ActOnEnumBody(StartLoc, T.getOpenLocation(), T.getCloseLocation(), + Actions.ActOnEnumBody(StartLoc, T.getRange(), EnumDecl, EnumConstantDecls, getCurScope(), attrs.getList()); @@ -4203,8 +4282,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { } EnumScope.Exit(); - Actions.ActOnTagFinishDefinition(getCurScope(), EnumDecl, - T.getCloseLocation()); + Actions.ActOnTagFinishDefinition(getCurScope(), EnumDecl, T.getRange()); // The next token must be valid after an enum definition. If not, a ';' // was probably forgotten. @@ -4219,27 +4297,6 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { } } -/// isTypeSpecifierQualifier - Return true if the current token could be the -/// start of a type-qualifier-list. -bool Parser::isTypeQualifier() const { - switch (Tok.getKind()) { - default: return false; - // type-qualifier - case tok::kw_const: - case tok::kw_volatile: - case tok::kw_restrict: - case tok::kw___private: - case tok::kw___local: - case tok::kw___global: - case tok::kw___constant: - case tok::kw___generic: - case tok::kw___read_only: - case tok::kw___read_write: - case tok::kw___write_only: - return true; - } -} - /// isKnownToBeTypeSpecifier - Return true if we know that the specified token /// is definitely a type-specifier. Return false if it isn't part of a type /// specifier or if we're not sure. @@ -4264,12 +4321,15 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_bool: case tok::kw__Bool: case tok::kw__Decimal32: case tok::kw__Decimal64: case tok::kw__Decimal128: case tok::kw___vector: +#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: +#include "clang/Basic/OpenCLImageTypes.def" // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: @@ -4336,12 +4396,15 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_bool: case tok::kw__Bool: case tok::kw__Decimal32: case tok::kw__Decimal64: case tok::kw__Decimal128: case tok::kw___vector: +#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: +#include "clang/Basic/OpenCLImageTypes.def" // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: @@ -4488,6 +4551,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_bool: case tok::kw__Bool: case tok::kw__Decimal32: @@ -4578,6 +4642,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw___read_only: case tok::kw___read_write: case tok::kw___write_only: +#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: +#include "clang/Basic/OpenCLImageTypes.def" return true; } @@ -4588,7 +4654,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) { // Parse the C++ scope specifier. CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + if (ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/true)) { TPA.Revert(); return false; @@ -4770,6 +4836,10 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs, ParseOpenCLQualifiers(DS.getAttributes()); break; + case tok::kw___unaligned: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_unaligned, Loc, PrevSpec, DiagID, + getLangOpts()); + break; case tok::kw___uptr: // GNU libc headers in C mode use '__uptr' as an identifer which conflicts // with the MS modifier keyword. @@ -4787,7 +4857,6 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs, case tok::kw___fastcall: case tok::kw___thiscall: case tok::kw___vectorcall: - case tok::kw___unaligned: if (AttrReqs & AR_DeclspecAttributesParsed) { ParseMicrosoftTypeAttributes(DS.getAttributes()); continue; @@ -4925,14 +4994,14 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // Member pointers get special handling, since there's no place for the // scope spec in the generic path below. if (getLangOpts().CPlusPlus && - (Tok.is(tok::coloncolon) || + (Tok.is(tok::coloncolon) || Tok.is(tok::kw_decltype) || (Tok.is(tok::identifier) && (NextToken().is(tok::coloncolon) || NextToken().is(tok::less))) || Tok.is(tok::annot_cxxscope))) { bool EnteringContext = D.getContext() == Declarator::FileContext || D.getContext() == Declarator::MemberContext; CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext); + ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext); if (SS.isNotEmpty()) { if (Tok.isNot(tok::star)) { @@ -4969,7 +5038,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D, tok::TokenKind Kind = Tok.getKind(); if (D.getDeclSpec().isTypeSpecPipe() && !isPipeDeclerator(D)) { - DeclSpec &DS = D.getMutableDeclSpec(); + DeclSpec DS(AttrFactory); + ParseTypeQualifierListOpt(DS); D.AddTypeInfo( DeclaratorChunk::getPipe(DS.getTypeQualifiers(), DS.getPipeLoc()), @@ -5009,7 +5079,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D, DS.getConstSpecLoc(), DS.getVolatileSpecLoc(), DS.getRestrictSpecLoc(), - DS.getAtomicSpecLoc()), + DS.getAtomicSpecLoc(), + DS.getUnalignedSpecLoc()), DS.getAttributes(), SourceLocation()); else @@ -5147,7 +5218,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (D.getCXXScopeSpec().isEmpty()) { bool EnteringContext = D.getContext() == Declarator::FileContext || D.getContext() == Declarator::MemberContext; - ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(), + ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), nullptr, EnteringContext); } @@ -5208,11 +5279,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { bool HadScope = D.getCXXScopeSpec().isValid(); if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*EnteringContext=*/true, - /*AllowDestructorName=*/true, - AllowConstructorName, - ParsedType(), - TemplateKWLoc, - D.getName()) || + /*AllowDestructorName=*/true, AllowConstructorName, + nullptr, TemplateKWLoc, D.getName()) || // Once we're past the identifier, if the scope was bad, mark the // whole declarator bad. D.getCXXScopeSpec().isInvalid()) { @@ -6013,6 +6081,9 @@ void Parser::ParseBracketDeclarator(Declarator &D) { T.getCloseLocation()), attrs, T.getCloseLocation()); return; + } else if (Tok.getKind() == tok::code_completion) { + Actions.CodeCompleteBracketDeclarator(getCurScope()); + return cutOffParsing(); } // If valid, this location is the position where we read the 'static' keyword. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 3f22ad4ddaba..6436e3dfc763 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -65,7 +65,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(unsigned Context, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteNamespaceDecl(getCurScope()); cutOffParsing(); - return DeclGroupPtrTy(); + return nullptr; } SourceLocation IdentLoc; @@ -109,7 +109,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(unsigned Context, Diag(Tok, diag::err_expected) << tok::identifier; // Skip to end of the definition and eat the ';'. SkipUntil(tok::semi); - return DeclGroupPtrTy(); + return nullptr; } if (attrLoc.isValid()) Diag(attrLoc, diag::err_unexpected_namespace_attributes_alias); @@ -126,7 +126,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(unsigned Context, Diag(Tok, diag::err_expected) << tok::l_brace; else Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace; - return DeclGroupPtrTy(); + return nullptr; } if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() || @@ -134,7 +134,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(unsigned Context, getCurScope()->getFnParent()) { Diag(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope); SkipUntil(tok::r_brace); - return DeclGroupPtrTy(); + return nullptr; } if (ExtraIdent.empty()) { @@ -267,7 +267,7 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, CXXScopeSpec SS; // Parse (optional) nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); if (SS.isInvalid() || Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_namespace_name); @@ -442,7 +442,7 @@ Decl *Parser::ParseUsingDirective(unsigned Context, CXXScopeSpec SS; // Parse (optional) nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); IdentifierInfo *NamespcName = nullptr; SourceLocation IdentLoc = SourceLocation(); @@ -517,7 +517,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, // Parse nested-name-specifier. IdentifierInfo *LastII = nullptr; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false, + ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false, /*MayBePseudoDtor=*/nullptr, /*IsTypename=*/false, /*LastII=*/&LastII); @@ -554,7 +554,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, /*AllowDestructorName=*/true, /*AllowConstructorName=*/!(Tok.is(tok::identifier) && NextToken().is(tok::equal)), - ParsedType(), TemplateKWLoc, Name)) { + nullptr, TemplateKWLoc, Name)) { SkipUntil(tok::semi); return nullptr; } @@ -944,7 +944,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, // Parse optional nested-name-specifier CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); BaseLoc = Tok.getLocation(); @@ -1006,8 +1006,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, if (!Template) { TemplateArgList TemplateArgs; SourceLocation LAngleLoc, RAngleLoc; - ParseTemplateIdAfterTemplateName(TemplateTy(), IdLoc, SS, - true, LAngleLoc, TemplateArgs, RAngleLoc); + ParseTemplateIdAfterTemplateName(nullptr, IdLoc, SS, true, LAngleLoc, + TemplateArgs, RAngleLoc); return true; } @@ -1037,11 +1037,10 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, // We have an identifier; check whether it is actually a type. IdentifierInfo *CorrectedII = nullptr; - ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true, - false, ParsedType(), - /*IsCtorOrDtorName=*/false, - /*NonTrivialTypeSourceInfo=*/true, - &CorrectedII); + ParsedType Type = + Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true, false, nullptr, + /*IsCtorOrDtorName=*/false, + /*NonTrivialTypeSourceInfo=*/true, &CorrectedII); if (!Type) { Diag(IdLoc, diag::err_expected_class_name); return true; @@ -1101,9 +1100,25 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { // FIXME: we should emit semantic diagnostic when declaration // attribute is in type attribute position. case tok::kw___attribute: // struct foo __attribute__((used)) x; + case tok::annot_pragma_pack: // struct foo {...} _Pragma(pack(pop)); + // struct foo {...} _Pragma(section(...)); + case tok::annot_pragma_ms_pragma: + // struct foo {...} _Pragma(vtordisp(pop)); + case tok::annot_pragma_ms_vtordisp: + // struct foo {...} _Pragma(pointers_to_members(...)); + case tok::annot_pragma_ms_pointers_to_members: return true; case tok::colon: return CouldBeBitfield; // enum E { ... } : 2; + // Microsoft compatibility + case tok::kw___cdecl: // struct foo {...} __cdecl x; + case tok::kw___fastcall: // struct foo {...} __fastcall x; + case tok::kw___stdcall: // struct foo {...} __stdcall x; + case tok::kw___thiscall: // struct foo {...} __thiscall x; + case tok::kw___vectorcall: // struct foo {...} __vectorcall x; + // We will diagnose these calling-convention specifiers on non-function + // declarations later, so claim they are valid after a type specifier. + return getLangOpts().MicrosoftExt; // Type qualifiers case tok::kw_const: // struct foo {...} const x; case tok::kw_volatile: // struct foo {...} volatile x; @@ -1261,6 +1276,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Tok.isOneOf(tok::kw___is_abstract, tok::kw___is_arithmetic, tok::kw___is_array, + tok::kw___is_assignable, tok::kw___is_base_of, tok::kw___is_class, tok::kw___is_complete_type, @@ -1352,7 +1368,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, CXXScopeSpec Spec; bool HasValidSpec = true; - if (ParseOptionalCXXScopeSpecifier(Spec, ParsedType(), EnteringContext)) { + if (ParseOptionalCXXScopeSpecifier(Spec, nullptr, EnteringContext)) { DS.SetTypeSpecError(); HasValidSpec = false; } @@ -1381,9 +1397,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // a class (or template thereof). TemplateArgList TemplateArgs; SourceLocation LAngleLoc, RAngleLoc; - if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, SS, - true, LAngleLoc, - TemplateArgs, RAngleLoc)) { + if (ParseTemplateIdAfterTemplateName( + nullptr, NameLoc, SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) { // We couldn't parse the template argument list at all, so don't // try to give any location information for the list. LAngleLoc = RAngleLoc = SourceLocation(); @@ -1396,7 +1411,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Strip off the last template parameter list if it was empty, since // we've removed its template argument list. if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) { - if (TemplateParams && TemplateParams->size() > 1) { + if (TemplateParams->size() > 1) { TemplateParams->pop_back(); } else { TemplateParams = nullptr; @@ -1663,7 +1678,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // template specialization. FakedParamLists.push_back(Actions.ActOnTemplateParameterList( 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, None, - LAngleLoc)); + LAngleLoc, nullptr)); TemplateParams = &FakedParamLists; } } @@ -2253,7 +2268,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ConsumeToken(); SkipUntil(tok::r_brace, StopAtSemi); - return DeclGroupPtrTy(); + return nullptr; } // Turn on colon protection early, while parsing declspec, although there is @@ -2282,28 +2297,28 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (isAccessDecl) { // Collect the scope specifier token we annotated earlier. CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); if (SS.isInvalid()) { SkipUntil(tok::semi); - return DeclGroupPtrTy(); + return nullptr; } // Try to parse an unqualified-id. SourceLocation TemplateKWLoc; UnqualifiedId Name; - if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), - TemplateKWLoc, Name)) { + if (ParseUnqualifiedId(SS, false, true, true, nullptr, TemplateKWLoc, + Name)) { SkipUntil(tok::semi); - return DeclGroupPtrTy(); + return nullptr; } // TODO: recover from mistakenly-qualified operator declarations. if (ExpectAndConsume(tok::semi, diag::err_expected_after, "access declaration")) { SkipUntil(tok::semi); - return DeclGroupPtrTy(); + return nullptr; } return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration( @@ -2361,7 +2376,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (Tok.is(tok::kw_namespace)) { Diag(UsingLoc, diag::err_using_namespace_in_class); SkipUntil(tok::semi, StopBeforeMatch); - return DeclGroupPtrTy(); + return nullptr; } SourceLocation DeclEnd; // Otherwise, it must be a using-declaration or an alias-declaration. @@ -2391,7 +2406,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate && DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_class, &CommonLateParsedAttrs)) - return DeclGroupPtrTy(); + return nullptr; MultiTemplateParamsArg TemplateParams( TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() @@ -2402,10 +2417,15 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (DS.isFriendSpecified()) ProhibitAttributes(FnAttrs); - Decl *TheDecl = - Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams); + RecordDecl *AnonRecord = nullptr; + Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec( + getCurScope(), AS, DS, TemplateParams, false, AnonRecord); DS.complete(TheDecl); - return DeclGroupPtrTy::make(DeclGroupRef(TheDecl)); + if (AnonRecord) { + Decl* decls[] = {AnonRecord, TheDecl}; + return Actions.BuildDeclaratorGroup(decls, /*TypeMayContainAuto=*/false); + } + return Actions.ConvertDeclToDeclGroup(TheDecl); } ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); @@ -2446,7 +2466,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (ParseCXXMemberDeclaratorBeforeInitializer( DeclaratorInfo, VS, BitfieldSize, LateParsedAttrs)) { TryConsumeToken(tok::semi); - return DeclGroupPtrTy(); + return nullptr; } // Check for a member function definition. @@ -2495,7 +2515,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Consume the optional ';' TryConsumeToken(tok::semi); - return DeclGroupPtrTy(); + return nullptr; } if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { @@ -2698,7 +2718,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); // If we stopped at a ';', eat it. TryConsumeToken(tok::semi); - return DeclGroupPtrTy(); + return nullptr; } return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup); @@ -2825,49 +2845,49 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( if (getLangOpts().MicrosoftExt && Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) { ParseMicrosoftIfExistsClassDeclaration(TagType, AS); - return DeclGroupPtrTy(); + return nullptr; } // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { ConsumeExtraSemi(InsideStruct, TagType); - return DeclGroupPtrTy(); + return nullptr; } if (Tok.is(tok::annot_pragma_vis)) { HandlePragmaVisibility(); - return DeclGroupPtrTy(); + return nullptr; } if (Tok.is(tok::annot_pragma_pack)) { HandlePragmaPack(); - return DeclGroupPtrTy(); + return nullptr; } if (Tok.is(tok::annot_pragma_align)) { HandlePragmaAlign(); - return DeclGroupPtrTy(); + return nullptr; } if (Tok.is(tok::annot_pragma_ms_pointers_to_members)) { HandlePragmaMSPointersToMembers(); - return DeclGroupPtrTy(); + return nullptr; } if (Tok.is(tok::annot_pragma_ms_pragma)) { HandlePragmaMSPragma(); - return DeclGroupPtrTy(); + return nullptr; } if (Tok.is(tok::annot_pragma_ms_vtordisp)) { HandlePragmaMSVtorDisp(); - return DeclGroupPtrTy(); + return nullptr; } // If we see a namespace here, a close brace was missing somewhere. if (Tok.is(tok::kw_namespace)) { DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl)); - return DeclGroupPtrTy(); + return nullptr; } AccessSpecifier NewAS = getAccessSpecifierIfPresent(); @@ -2903,11 +2923,12 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( AccessAttrs.clear(); } - return DeclGroupPtrTy(); + return nullptr; } if (Tok.is(tok::annot_pragma_openmp)) - return ParseOpenMPDeclarativeDirective(); + return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, AccessAttrs, TagType, + TagDecl); // Parse all the comma separated declarators. return ParseCXXClassMemberDeclaration(AS, AccessAttrs.getList()); @@ -3122,8 +3143,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, } if (TagDecl) - Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, - T.getCloseLocation()); + Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, T.getRange()); // Leave the class scope. ParsingDef.Pop(); @@ -3189,28 +3209,30 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { Actions.CodeCompleteConstructorInitializer(ConstructorDecl, MemInitializers); return cutOffParsing(); - } else { - MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); - if (!MemInit.isInvalid()) - MemInitializers.push_back(MemInit.get()); - else - AnyErrors = true; } - + + MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); + if (!MemInit.isInvalid()) + MemInitializers.push_back(MemInit.get()); + else + AnyErrors = true; + if (Tok.is(tok::comma)) ConsumeToken(); else if (Tok.is(tok::l_brace)) break; - // If the next token looks like a base or member initializer, assume that - // we're just missing a comma. - else if (Tok.isOneOf(tok::identifier, tok::coloncolon)) { + // If the previous initializer was valid and the next token looks like a + // base or member initializer, assume that we're just missing a comma. + else if (!MemInit.isInvalid() && + Tok.isOneOf(tok::identifier, tok::coloncolon)) { SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation); Diag(Loc, diag::err_ctor_init_missing_comma) << FixItHint::CreateInsertion(Loc, ", "); } else { // Skip over garbage, until we get to '{'. Don't eat the '{'. - Diag(Tok.getLocation(), diag::err_expected_either) << tok::l_brace - << tok::comma; + if (!MemInit.isInvalid()) + Diag(Tok.getLocation(), diag::err_expected_either) << tok::l_brace + << tok::comma; SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch); break; } @@ -3235,7 +3257,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { // parse '::'[opt] nested-name-specifier[opt] CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); ParsedType TemplateTypeTy; if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); @@ -3397,10 +3419,11 @@ Parser::tryParseExceptionSpecification(bool Delayed, NoexceptExpr = ParseConstantExpression(); T.consumeClose(); // The argument must be contextually convertible to bool. We use - // ActOnBooleanCondition for this purpose. + // CheckBooleanCondition for this purpose. + // FIXME: Add a proper Sema entry point for this. if (!NoexceptExpr.isInvalid()) { - NoexceptExpr = Actions.ActOnBooleanCondition(getCurScope(), KeywordLoc, - NoexceptExpr.get()); + NoexceptExpr = + Actions.CheckBooleanCondition(KeywordLoc, NoexceptExpr.get()); NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation()); } else { NoexceptType = EST_None; @@ -3630,7 +3653,10 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName, case AttributeList::AT_FallThrough: case AttributeList::AT_CXX11NoReturn: return true; - + case AttributeList::AT_WarnUnusedResult: + return !ScopeName && AttrName->getName().equals("nodiscard"); + case AttributeList::AT_Unused:
+ return !ScopeName && AttrName->getName().equals("maybe_unused");
default: return false; } @@ -3689,6 +3715,7 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, // The attribute was allowed to have arguments, but none were provided // even though the attribute parsed successfully. This is an error. Diag(LParenLoc, diag::err_attribute_requires_arguments) << AttrName; + Attr->setInvalid(true); } else if (!Attr->getMaxArgs()) { // The attribute parsed successfully, but was not allowed to have any // arguments. It doesn't matter whether any were provided -- the @@ -3696,6 +3723,7 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, Diag(LParenLoc, diag::err_cxx11_attribute_forbids_arguments) << AttrName << FixItHint::CreateRemoval(SourceRange(LParenLoc, *EndLoc)); + Attr->setInvalid(true); } } } @@ -3742,6 +3770,23 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, ConsumeBracket(); ConsumeBracket(); + SourceLocation CommonScopeLoc; + IdentifierInfo *CommonScopeName = nullptr; + if (Tok.is(tok::kw_using)) { + Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z + ? diag::warn_cxx14_compat_using_attribute_ns + : diag::ext_using_attribute_ns); + ConsumeToken(); + + CommonScopeName = TryParseCXX11AttributeIdentifier(CommonScopeLoc); + if (!CommonScopeName) { + Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; + SkipUntil(tok::r_square, tok::colon, StopBeforeMatch); + } + if (!TryConsumeToken(tok::colon) && CommonScopeName) + Diag(Tok.getLocation(), diag::err_expected) << tok::colon; + } + llvm::SmallDenseMap<IdentifierInfo*, SourceLocation, 4> SeenAttrs; while (Tok.isNot(tok::r_square)) { @@ -3770,6 +3815,16 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, } } + if (CommonScopeName) { + if (ScopeName) { + Diag(ScopeLoc, diag::err_using_attribute_ns_conflict) + << SourceRange(CommonScopeLoc); + } else { + ScopeName = CommonScopeName; + ScopeLoc = CommonScopeLoc; + } + } + bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName); bool AttrParsed = false; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 1fd98c140e0e..47d1326b7989 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -263,6 +263,9 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { Token OpToken = Tok; ConsumeToken(); + if (OpToken.is(tok::caretcaret)) { + return ExprError(Diag(Tok, diag::err_opencl_logical_exclusive_or)); + } // Bail out when encountering a comma followed by a token which can't // possibly be the start of an expression. For instance: // int f() { return 1, } @@ -428,6 +431,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { } } + ExprResult OrigLHS = LHS; if (!LHS.isInvalid()) { // Combine the LHS and RHS into the LHS (e.g. build AST). if (TernaryMiddle.isInvalid()) { @@ -442,13 +446,22 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { LHS = Actions.ActOnBinOp(getCurScope(), OpToken.getLocation(), OpToken.getKind(), LHS.get(), RHS.get()); - } else + + // In this case, ActOnBinOp performed the CorrectDelayedTyposInExpr check. + if (!getLangOpts().CPlusPlus) + continue; + } else { LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc, LHS.get(), TernaryMiddle.get(), RHS.get()); - } else - // Ensure potential typos in the RHS aren't left undiagnosed. + } + } + // Ensure potential typos aren't left undiagnosed. + if (LHS.isInvalid()) { + Actions.CorrectDelayedTyposInExpr(OrigLHS); + Actions.CorrectDelayedTyposInExpr(TernaryMiddle); Actions.CorrectDelayedTyposInExpr(RHS); + } } } @@ -513,7 +526,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { /// \p isAddressOfOperand exists because an id-expression that is the operand /// of address-of gets special treatment due to member pointers. NotCastExpr /// is set to true if the token is not the start of a cast-expression, and no -/// diagnostic is emitted in this case. +/// diagnostic is emitted in this case and no tokens are consumed. /// /// \verbatim /// cast-expression: [C99 6.5.4] @@ -787,6 +800,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, REVERTIBLE_TYPE_TRAIT(__is_abstract); REVERTIBLE_TYPE_TRAIT(__is_arithmetic); REVERTIBLE_TYPE_TRAIT(__is_array); + REVERTIBLE_TYPE_TRAIT(__is_assignable); REVERTIBLE_TYPE_TRAIT(__is_base_of); REVERTIBLE_TYPE_TRAIT(__is_class); REVERTIBLE_TYPE_TRAIT(__is_complete_type); @@ -895,7 +909,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ((Tok.is(tok::identifier) && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) || Tok.is(tok::code_completion))) { - Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, ParsedType(), + Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, nullptr, nullptr); break; } @@ -995,6 +1009,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1] Res = ParseGenericSelectionExpression(); break; + case tok::kw___builtin_available: + return ParseAvailabilityCheckExpr(Tok.getLocation()); case tok::kw___builtin_va_arg: case tok::kw___builtin_offsetof: case tok::kw___builtin_choose_expr: @@ -1010,15 +1026,24 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // unary-expression: // ++ cast-expression // -- cast-expression - SourceLocation SavedLoc = ConsumeToken(); + Token SavedTok = Tok; + ConsumeToken(); // One special case is implicitly handled here: if the preceding tokens are // an ambiguous cast expression, such as "(T())++", then we recurse to // determine whether the '++' is prefix or postfix. Res = ParseCastExpression(!getLangOpts().CPlusPlus, /*isAddressOfOperand*/false, NotCastExpr, NotTypeCast); + if (NotCastExpr) { + // If we return with NotCastExpr = true, we must not consume any tokens, + // so put the token back where we found it. + assert(Res.isInvalid()); + UnconsumeToken(SavedTok); + return ExprError(); + } if (!Res.isInvalid()) - Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); + Res = Actions.ActOnUnaryOp(getCurScope(), SavedTok.getLocation(), + SavedKind, Res.get()); return Res; } case tok::amp: { // unary-expression: '&' cast-expression @@ -1148,10 +1173,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_void: case tok::kw_typename: case tok::kw_typeof: - case tok::kw___vector: { + case tok::kw___vector: +#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: +#include "clang/Basic/OpenCLImageTypes.def" + { if (!getLangOpts().CPlusPlus) { Diag(Tok, diag::err_expected_expression); return ExprError(); @@ -1204,7 +1233,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // type, translate it into a type and continue parsing as a // cast expression. CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); AnnotateTemplateIdTokenAsType(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, @@ -1395,7 +1424,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (getLangOpts().ObjC1 && !InMessageExpression && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { LHS = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), - ParsedType(), LHS.get()); + nullptr, LHS.get()); break; } @@ -1416,8 +1445,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Reject array indices starting with a lambda-expression. '[[' is // reserved for attributes. - if (CheckProhibitedCXX11Attribute()) + if (CheckProhibitedCXX11Attribute()) { + (void)Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); + } BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); @@ -1445,6 +1476,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { SourceLocation RLoc = Tok.getLocation(); + ExprResult OrigLHS = LHS; if (!LHS.isInvalid() && !Idx.isInvalid() && !Length.isInvalid() && Tok.is(tok::r_square)) { if (ColonLoc.isValid()) { @@ -1455,7 +1487,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { Idx.get(), RLoc); } } else { - (void)Actions.CorrectDelayedTyposInExpr(LHS); + LHS = ExprError(); + } + if (LHS.isInvalid()) { + (void)Actions.CorrectDelayedTyposInExpr(OrigLHS); (void)Actions.CorrectDelayedTyposInExpr(Idx); (void)Actions.CorrectDelayedTyposInExpr(Length); LHS = ExprError(); @@ -1606,7 +1641,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /*EnteringContext=*/false, &MayBePseudoDestructor); if (SS.isNotEmpty()) - ObjectType = ParsedType(); + ObjectType = nullptr; } if (Tok.is(tok::code_completion)) { @@ -2160,7 +2195,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, ExprResult Result(true); bool isAmbiguousTypeId; - CastTy = ParsedType(); + CastTy = nullptr; if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), @@ -2506,7 +2541,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { return ExprError(); } DefaultLoc = ConsumeToken(); - Ty = ParsedType(); + Ty = nullptr; } else { ColonProtectionRAIIObject X(*this); TypeResult TR = ParseTypeName(); @@ -2836,3 +2871,117 @@ ExprResult Parser::ParseObjCBoolLiteral() { tok::TokenKind Kind = Tok.getKind(); return Actions.ActOnObjCBoolLiteral(ConsumeToken(), Kind); } + +/// Validate availability spec list, emitting diagnostics if necessary. Returns +/// true if invalid. +static bool CheckAvailabilitySpecList(Parser &P, + ArrayRef<AvailabilitySpec> AvailSpecs) { + llvm::SmallSet<StringRef, 4> Platforms; + bool HasOtherPlatformSpec = false; + bool Valid = true; + for (const auto &Spec : AvailSpecs) { + if (Spec.isOtherPlatformSpec()) { + if (HasOtherPlatformSpec) { + P.Diag(Spec.getBeginLoc(), diag::err_availability_query_repeated_star); + Valid = false; + } + + HasOtherPlatformSpec = true; + continue; + } + + bool Inserted = Platforms.insert(Spec.getPlatform()).second; + if (!Inserted) { + // Rule out multiple version specs referring to the same platform. + // For example, we emit an error for: + // @available(macos 10.10, macos 10.11, *) + StringRef Platform = Spec.getPlatform(); + P.Diag(Spec.getBeginLoc(), diag::err_availability_query_repeated_platform) + << Spec.getEndLoc() << Platform; + Valid = false; + } + } + + if (!HasOtherPlatformSpec) { + SourceLocation InsertWildcardLoc = AvailSpecs.back().getEndLoc(); + P.Diag(InsertWildcardLoc, diag::err_availability_query_wildcard_required) + << FixItHint::CreateInsertion(InsertWildcardLoc, ", *"); + return true; + } + + return !Valid; +} + +/// Parse availability query specification. +/// +/// availability-spec: +/// '*' +/// identifier version-tuple +Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() { + if (Tok.is(tok::star)) { + return AvailabilitySpec(ConsumeToken()); + } else { + // Parse the platform name. + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_avail_query_expected_platform_name); + return None; + } + + IdentifierLoc *PlatformIdentifier = ParseIdentifierLoc(); + SourceRange VersionRange; + VersionTuple Version = ParseVersionTuple(VersionRange); + + if (Version.empty()) + return None; + + StringRef Platform = PlatformIdentifier->Ident->getName(); + + if (AvailabilityAttr::getPrettyPlatformName(Platform).empty()) { + Diag(PlatformIdentifier->Loc, + diag::err_avail_query_unrecognized_platform_name) + << Platform; + return None; + } + + return AvailabilitySpec(Version, Platform, PlatformIdentifier->Loc, + VersionRange.getEnd()); + } +} + +ExprResult Parser::ParseAvailabilityCheckExpr(SourceLocation BeginLoc) { + assert(Tok.is(tok::kw___builtin_available) || + Tok.isObjCAtKeyword(tok::objc_available)); + + // Eat the available or __builtin_available. + ConsumeToken(); + + BalancedDelimiterTracker Parens(*this, tok::l_paren); + if (Parens.expectAndConsume()) + return ExprError(); + + SmallVector<AvailabilitySpec, 4> AvailSpecs; + bool HasError = false; + while (true) { + Optional<AvailabilitySpec> Spec = ParseAvailabilitySpec(); + if (!Spec) + HasError = true; + else + AvailSpecs.push_back(*Spec); + + if (!TryConsumeToken(tok::comma)) + break; + } + + if (HasError) { + SkipUntil(tok::r_paren, StopAtSemi); + return ExprError(); + } + + CheckAvailabilitySpecList(*this, AvailSpecs); + + if (Parens.consumeClose()) + return ExprError(); + + return Actions.ActOnObjCAvailabilityCheckExpr(AvailSpecs, BeginLoc, + Parens.getCloseLocation()); +} diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index f8938ba3495b..b09d7dbc12fc 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -283,8 +283,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // // To implement this, we clear out the object type as soon as we've // seen a leading '::' or part of a nested-name-specifier. - ObjectType = ParsedType(); - + ObjectType = nullptr; + if (Tok.is(tok::code_completion)) { // Code completion for a nested-name-specifier, where the code // code completion token follows the '::'. @@ -597,7 +597,7 @@ ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOpe /*EnteringContext=*/false, /*AllowDestructorName=*/false, /*AllowConstructorName=*/false, - /*ObjectType=*/ParsedType(), TemplateKWLoc, Name)) + /*ObjectType=*/nullptr, TemplateKWLoc, Name)) return ExprError(); // This is only the direct operand of an & operator if it is not @@ -659,7 +659,7 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // '::' unqualified-id // CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); Token Replacement; ExprResult Result = @@ -739,8 +739,11 @@ ExprResult Parser::TryParseLambdaExpression() { && Tok.is(tok::l_square) && "Not at the start of a possible lambda expression."); - const Token Next = NextToken(), After = GetLookAheadToken(2); + const Token Next = NextToken(); + if (Next.is(tok::eof)) // Nothing else to lookup here... + return ExprEmpty(); + const Token After = GetLookAheadToken(2); // If lookahead indicates this is a lambda... if (Next.is(tok::r_square) || // [] Next.is(tok::equal) || // [= @@ -846,8 +849,16 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, IdentifierInfo *Id = nullptr; SourceLocation EllipsisLoc; ExprResult Init; - - if (Tok.is(tok::kw_this)) { + + if (Tok.is(tok::star)) { + Loc = ConsumeToken(); + if (Tok.is(tok::kw_this)) { + ConsumeToken(); + Kind = LCK_StarThis; + } else { + return DiagResult(diag::err_expected_star_this_capture); + } + } else if (Tok.is(tok::kw_this)) { Kind = LCK_This; Loc = ConsumeToken(); } else { @@ -1042,6 +1053,58 @@ bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) { return false; } +static void +tryConsumeMutableOrConstexprToken(Parser &P, SourceLocation &MutableLoc, + SourceLocation &ConstexprLoc, + SourceLocation &DeclEndLoc) { + assert(MutableLoc.isInvalid()); + assert(ConstexprLoc.isInvalid()); + // Consume constexpr-opt mutable-opt in any sequence, and set the DeclEndLoc + // to the final of those locations. Emit an error if we have multiple + // copies of those keywords and recover. + + while (true) { + switch (P.getCurToken().getKind()) { + case tok::kw_mutable: { + if (MutableLoc.isValid()) { + P.Diag(P.getCurToken().getLocation(), + diag::err_lambda_decl_specifier_repeated) + << 0 << FixItHint::CreateRemoval(P.getCurToken().getLocation()); + } + MutableLoc = P.ConsumeToken(); + DeclEndLoc = MutableLoc; + break /*switch*/; + } + case tok::kw_constexpr: + if (ConstexprLoc.isValid()) { + P.Diag(P.getCurToken().getLocation(), + diag::err_lambda_decl_specifier_repeated) + << 1 << FixItHint::CreateRemoval(P.getCurToken().getLocation()); + } + ConstexprLoc = P.ConsumeToken(); + DeclEndLoc = ConstexprLoc; + break /*switch*/; + default: + return; + } + } +} + +static void +addConstexprToLambdaDeclSpecifier(Parser &P, SourceLocation ConstexprLoc, + DeclSpec &DS) { + if (ConstexprLoc.isValid()) { + P.Diag(ConstexprLoc, !P.getLangOpts().CPlusPlus1z + ? diag::ext_constexpr_on_lambda_cxx1z + : diag::warn_cxx14_compat_constexpr_on_lambda); + const char *PrevSpec = nullptr; + unsigned DiagID = 0; + DS.SetConstexprSpec(ConstexprLoc, PrevSpec, DiagID); + assert(PrevSpec == nullptr && DiagID == 0 && + "Constexpr cannot have been set previously!"); + } +} + /// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda /// expression. ExprResult Parser::ParseLambdaExpressionAfterIntroducer( @@ -1100,10 +1163,13 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( // compatible with MSVC. MaybeParseMicrosoftDeclSpecs(Attr, &DeclEndLoc); - // Parse 'mutable'[opt]. + // Parse mutable-opt and/or constexpr-opt, and update the DeclEndLoc. SourceLocation MutableLoc; - if (TryConsumeToken(tok::kw_mutable, MutableLoc)) - DeclEndLoc = MutableLoc; + SourceLocation ConstexprLoc; + tryConsumeMutableOrConstexprToken(*this, MutableLoc, ConstexprLoc, + DeclEndLoc); + + addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS); // Parse exception-specification[opt]. ExceptionSpecificationType ESpecType = EST_None; @@ -1161,7 +1227,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( LParenLoc, FunLocalRangeEnd, D, TrailingReturnType), Attr, DeclEndLoc); - } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute) || + } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute, + tok::kw_constexpr) || (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) { // It's common to forget that one needs '()' before 'mutable', an attribute // specifier, or the result type. Deal with this. @@ -1171,6 +1238,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( case tok::arrow: TokKind = 1; break; case tok::kw___attribute: case tok::l_square: TokKind = 2; break; + case tok::kw_constexpr: TokKind = 3; break; default: llvm_unreachable("Unknown token kind"); } @@ -1658,46 +1726,58 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression /// -/// \param ExprOut if the condition was parsed as an expression, the parsed -/// expression. +/// In C++1z, a condition may in some contexts be preceded by an +/// optional init-statement. This function will parse that too. /// -/// \param DeclOut if the condition was parsed as a declaration, the parsed -/// declaration. +/// \param InitStmt If non-null, an init-statement is permitted, and if present +/// will be parsed and stored here. /// /// \param Loc The location of the start of the statement that requires this /// condition, e.g., the "for" in a for loop. /// -/// \param ConvertToBoolean Whether the condition expression should be -/// converted to a boolean value. -/// -/// \returns true if there was a parsing, false otherwise. -bool Parser::ParseCXXCondition(ExprResult &ExprOut, - Decl *&DeclOut, - SourceLocation Loc, - bool ConvertToBoolean) { +/// \returns The parsed condition. +Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, + SourceLocation Loc, + Sema::ConditionKind CK) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition); cutOffParsing(); - return true; + return Sema::ConditionError(); } ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); - if (!isCXXConditionDeclaration()) { + // Determine what kind of thing we have. + switch (isCXXConditionDeclarationOrInitStatement(InitStmt)) { + case ConditionOrInitStatement::Expression: { ProhibitAttributes(attrs); // Parse the expression. - ExprOut = ParseExpression(); // expression - DeclOut = nullptr; - if (ExprOut.isInvalid()) - return true; + ExprResult Expr = ParseExpression(); // expression + if (Expr.isInvalid()) + return Sema::ConditionError(); + + if (InitStmt && Tok.is(tok::semi)) { + *InitStmt = Actions.ActOnExprStmt(Expr.get()); + ConsumeToken(); + return ParseCXXCondition(nullptr, Loc, CK); + } + + return Actions.ActOnCondition(getCurScope(), Loc, Expr.get(), CK); + } + + case ConditionOrInitStatement::InitStmtDecl: { + SourceLocation DeclStart = Tok.getLocation(), DeclEnd; + DeclGroupPtrTy DG = ParseSimpleDeclaration( + Declarator::InitStmtContext, DeclEnd, attrs, /*RequireSemi=*/true); + *InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd); + return ParseCXXCondition(nullptr, Loc, CK); + } - // If required, convert to a boolean value. - if (ConvertToBoolean) - ExprOut - = Actions.ActOnBooleanCondition(getCurScope(), Loc, ExprOut.get()); - return ExprOut.isInvalid(); + case ConditionOrInitStatement::ConditionDecl: + case ConditionOrInitStatement::Error: + break; } // type-specifier-seq @@ -1715,7 +1795,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, ExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) { SkipUntil(tok::semi, StopAtSemi); - return true; + return Sema::ConditionError(); } DeclaratorInfo.setAsmLabel(AsmLabel.get()); DeclaratorInfo.SetRangeEnd(Loc); @@ -1727,8 +1807,9 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, // Type-check the declaration itself. DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(getCurScope(), DeclaratorInfo); - DeclOut = Dcl.get(); - ExprOut = ExprError(); + if (Dcl.isInvalid()) + return Sema::ConditionError(); + Decl *DeclOut = Dcl.get(); // '=' assignment-expression // If a '==' or '+=' is found, suggest a fixit to '='. @@ -1748,12 +1829,11 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, SourceLocation LParen = ConsumeParen(), RParen = LParen; if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) RParen = ConsumeParen(); - Diag(DeclOut ? DeclOut->getLocation() : LParen, + Diag(DeclOut->getLocation(), diag::err_expected_init_in_condition_lparen) << SourceRange(LParen, RParen); } else { - Diag(DeclOut ? DeclOut->getLocation() : Tok.getLocation(), - diag::err_expected_init_in_condition); + Diag(DeclOut->getLocation(), diag::err_expected_init_in_condition); } if (!InitExpr.isInvalid()) @@ -1762,12 +1842,8 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, else Actions.ActOnInitializerError(DeclOut); - // FIXME: Build a reference to this declaration? Convert it to bool? - // (This is currently handled by Sema). - Actions.FinalizeDeclaration(DeclOut); - - return false; + return Actions.ActOnConditionVariable(DeclOut, Loc, CK); } /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. @@ -1863,6 +1939,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { case tok::kw_double: DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID, Policy); break; + case tok::kw___float128: + DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec, DiagID, Policy); + break; case tok::kw_wchar_t: DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID, Policy); break; @@ -2413,9 +2492,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, if (AllowConstructorName && Actions.isCurrentClassName(*Id, getCurScope(), &SS)) { // We have parsed a constructor name. - ParsedType Ty = Actions.getTypeName(*Id, IdLoc, getCurScope(), - &SS, false, false, - ParsedType(), + ParsedType Ty = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, false, + false, nullptr, /*IsCtorOrDtorName=*/true, /*NonTrivialTypeSourceInfo=*/true); Result.setConstructorName(Ty, IdLoc, IdLoc); @@ -2451,13 +2529,11 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, << TemplateId->Name << FixItHint::CreateRemoval( SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)); - ParsedType Ty = Actions.getTypeName(*TemplateId->Name, - TemplateId->TemplateNameLoc, - getCurScope(), - &SS, false, false, - ParsedType(), - /*IsCtorOrDtorName=*/true, - /*NontrivialTypeSourceInfo=*/true); + ParsedType Ty = + Actions.getTypeName(*TemplateId->Name, TemplateId->TemplateNameLoc, + getCurScope(), &SS, false, false, nullptr, + /*IsCtorOrDtorName=*/true, + /*NontrivialTypeSourceInfo=*/true); Result.setConstructorName(Ty, TemplateId->TemplateNameLoc, TemplateId->RAngleLoc); ConsumeToken(); @@ -2541,7 +2617,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, if (ParseOptionalCXXScopeSpecifier(SS, ObjectType, EnteringContext)) return true; if (SS.isNotEmpty()) - ObjectType = ParsedType(); + ObjectType = nullptr; if (Tok.isNot(tok::identifier) || NextToken().is(tok::coloncolon) || !SS.isSet()) { Diag(TildeLoc, diag::err_destructor_tilde_scope); @@ -2563,7 +2639,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, SourceLocation ClassNameLoc = ConsumeToken(); if (TemplateSpecified || Tok.is(tok::less)) { - Result.setDestructorName(TildeLoc, ParsedType(), ClassNameLoc); + Result.setDestructorName(TildeLoc, nullptr, ClassNameLoc); return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, ClassName, ClassNameLoc, EnteringContext, ObjectType, @@ -3029,7 +3105,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, assert(isTypeIdInParens() && "Not a type-id!"); ExprResult Result(true); - CastTy = ParsedType(); + CastTy = nullptr; // We need to disambiguate a very ugly part of the C++ syntax: // @@ -3084,12 +3160,19 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, ParseAs = NotCastExpr ? SimpleExpr : CastExpr; } + // Create a fake EOF to mark end of Toks buffer. + Token AttrEnd; + AttrEnd.startToken(); + AttrEnd.setKind(tok::eof); + AttrEnd.setLocation(Tok.getLocation()); + AttrEnd.setEofData(Toks.data()); + Toks.push_back(AttrEnd); + // The current token should go after the cached tokens. Toks.push_back(Tok); // Re-enter the stored parenthesized tokens into the token stream, so we may // parse them now. - PP.EnterTokenStream(Toks.data(), Toks.size(), - true/*DisableMacroExpansion*/, false/*OwnsTokens*/); + PP.EnterTokenStream(Toks, true /*DisableMacroExpansion*/); // Drop the current token and bring the first cached one. It's the same token // as when we entered this function. ConsumeAnyToken(); @@ -3108,6 +3191,10 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, Tracker.consumeClose(); ColonProt.restore(); + // Consume EOF marker for Toks buffer. + assert(Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData()); + ConsumeAnyToken(); + if (ParseAs == CompoundLiteral) { ExprType = CompoundLiteral; if (DeclaratorInfo.isInvalidType()) @@ -3144,10 +3231,16 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, // Match the ')'. if (Result.isInvalid()) { - SkipUntil(tok::r_paren, StopAtSemi); + while (Tok.isNot(tok::eof)) + ConsumeAnyToken(); + assert(Tok.getEofData() == AttrEnd.getEofData()); + ConsumeAnyToken(); return ExprError(); } Tracker.consumeClose(); + // Consume EOF marker for Toks buffer. + assert(Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData()); + ConsumeAnyToken(); return Result; } diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 4896ff0d235a..2cdb9d3a22a6 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -216,10 +216,8 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope()) { CheckArrayDesignatorSyntax(*this, StartLoc, Desig); - return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, - ConsumeToken(), - ParsedType(), - nullptr); + return ParseAssignmentExprWithObjCMessageExprStart( + StartLoc, ConsumeToken(), nullptr, nullptr); } // Parse the receiver, which is either a type or an expression. @@ -257,10 +255,8 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { NextToken().is(tok::period), ReceiverType)) { case Sema::ObjCSuperMessage: CheckArrayDesignatorSyntax(*this, StartLoc, Desig); - return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, - ConsumeToken(), - ParsedType(), - nullptr); + return ParseAssignmentExprWithObjCMessageExprStart( + StartLoc, ConsumeToken(), nullptr, nullptr); case Sema::ObjCClassMessage: CheckArrayDesignatorSyntax(*this, StartLoc, Desig); @@ -320,10 +316,8 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { if (getLangOpts().ObjC1 && Tok.isNot(tok::ellipsis) && Tok.isNot(tok::r_square)) { CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig); - return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, - SourceLocation(), - ParsedType(), - Idx.get()); + return ParseAssignmentExprWithObjCMessageExprStart( + StartLoc, SourceLocation(), nullptr, Idx.get()); } // If this is a normal array designator, remember it. diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index e72a1f62f942..67abe5839bfe 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -21,6 +21,7 @@ #include "clang/Sema/Scope.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" + using namespace clang; /// Skips attributes after an Objective-C @ directive. Emits a diagnostic. @@ -50,7 +51,7 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCAtDirective(getCurScope()); cutOffParsing(); - return DeclGroupPtrTy(); + return nullptr; } Decl *SingleDecl = nullptr; @@ -99,16 +100,20 @@ class Parser::ObjCTypeParamListScope { Sema &Actions; Scope *S; ObjCTypeParamList *Params; + public: ObjCTypeParamListScope(Sema &Actions, Scope *S) : Actions(Actions), S(S), Params(nullptr) {} + ~ObjCTypeParamListScope() { leave(); } + void enter(ObjCTypeParamList *P) { assert(!Params); Params = P; } + void leave() { if (Params) Actions.popObjCTypeParamList(S, Params); @@ -334,16 +339,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, // Type arguments for the superclass or protocol conformances. if (Tok.is(tok::less)) { - parseObjCTypeArgsOrProtocolQualifiers(ParsedType(), - typeArgsLAngleLoc, - typeArgs, - typeArgsRAngleLoc, - LAngleLoc, - protocols, - protocolLocs, - EndProtoLoc, - /*consumeLastToken=*/true, - /*warnOnIncompleteProtocols=*/true); + parseObjCTypeArgsOrProtocolQualifiers( + nullptr, typeArgsLAngleLoc, typeArgs, typeArgsRAngleLoc, LAngleLoc, + protocols, protocolLocs, EndProtoLoc, + /*consumeLastToken=*/true, + /*warnOnIncompleteProtocols=*/true); } } @@ -459,14 +459,8 @@ ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs( unsigned index = 0; for (const auto &pair : protocolIdents) { DeclResult typeParam = Actions.actOnObjCTypeParam( - getCurScope(), - ObjCTypeParamVariance::Invariant, - SourceLocation(), - index++, - pair.first, - pair.second, - SourceLocation(), - ParsedType()); + getCurScope(), ObjCTypeParamVariance::Invariant, SourceLocation(), + index++, pair.first, pair.second, SourceLocation(), nullptr); if (typeParam.isUsable()) typeParams.push_back(typeParam.get()); } @@ -542,16 +536,9 @@ ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs( } // Create the type parameter. - DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(), - variance, - varianceLoc, - typeParams.size(), - paramName, - paramLoc, - colonLoc, - boundType.isUsable() - ? boundType.get() - : ParsedType()); + DeclResult typeParam = Actions.actOnObjCTypeParam( + getCurScope(), variance, varianceLoc, typeParams.size(), paramName, + paramLoc, colonLoc, boundType.isUsable() ? boundType.get() : nullptr); if (typeParam.isUsable()) typeParams.push_back(typeParam.get()); } while (TryConsumeToken(tok::comma)); @@ -865,6 +852,7 @@ static void diagnoseRedundantPropertyNullability(Parser &P, /// nullable /// null_unspecified /// null_resettable +/// class /// void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { assert(Tok.getKind() == tok::l_paren); @@ -980,6 +968,8 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { // Also set the null_resettable bit. DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_null_resettable); + } else if (II->isStr("class")) { + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_class); } else { Diag(AttrName, diag::err_objc_expected_property_attr) << II; SkipUntil(tok::r_paren, StopAtSemi); @@ -1287,7 +1277,6 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, if (context == Declarator::ObjCResultContext) dsContext = DSC_objc_method_result; ParseSpecifierQualifierList(declSpec, AS_none, dsContext); - declSpec.SetRangeEnd(Tok.getLocation()); Declarator declarator(declSpec, context); ParseDeclarator(declarator); @@ -1361,8 +1350,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent); if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, - /*ReturnType=*/ ParsedType()); + Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, + /*ReturnType=*/nullptr); cutOffParsing(); return nullptr; } @@ -1432,7 +1421,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, if (ExpectAndConsume(tok::colon)) break; - ArgInfo.Type = ParsedType(); + ArgInfo.Type = nullptr; if (Tok.is(tok::l_paren)) // Parse the argument type if present. ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, Declarator::ObjCParameterContext, @@ -1703,11 +1692,18 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers( return; } - // We syntactically matched a type argument, so commit to parsing - // type arguments. + // We parsed an identifier list but stumbled into non single identifiers, this + // means we might (a) check that what we already parsed is a legitimate type + // (not a protocol or unknown type) and (b) parse the remaining ones, which + // must all be type args. // Convert the identifiers into type arguments. bool invalid = false; + IdentifierInfo *foundProtocolId = nullptr, *foundValidTypeId = nullptr; + SourceLocation foundProtocolSrcLoc, foundValidTypeSrcLoc; + SmallVector<IdentifierInfo *, 2> unknownTypeArgs; + SmallVector<SourceLocation, 2> unknownTypeArgsLoc; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { ParsedType typeArg = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope()); @@ -1721,17 +1717,32 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers( // Form a declarator to turn this into a type. Declarator D(DS, Declarator::TypeNameContext); TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D); - if (fullTypeArg.isUsable()) + if (fullTypeArg.isUsable()) { typeArgs.push_back(fullTypeArg.get()); - else + if (!foundValidTypeId) { + foundValidTypeId = identifiers[i]; + foundValidTypeSrcLoc = identifierLocs[i]; + } + } else { invalid = true; + unknownTypeArgs.push_back(identifiers[i]); + unknownTypeArgsLoc.push_back(identifierLocs[i]); + } } else { invalid = true; + if (!Actions.LookupProtocol(identifiers[i], identifierLocs[i])) { + unknownTypeArgs.push_back(identifiers[i]); + unknownTypeArgsLoc.push_back(identifierLocs[i]); + } else if (!foundProtocolId) { + foundProtocolId = identifiers[i]; + foundProtocolSrcLoc = identifierLocs[i]; + } } } // Continue parsing type-names. do { + Token CurTypeTok = Tok; TypeResult typeArg = ParseTypeName(); // Consume the '...' for a pack expansion. @@ -1743,11 +1754,28 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers( if (typeArg.isUsable()) { typeArgs.push_back(typeArg.get()); + if (!foundValidTypeId) { + foundValidTypeId = CurTypeTok.getIdentifierInfo(); + foundValidTypeSrcLoc = CurTypeTok.getLocation(); + } } else { invalid = true; } } while (TryConsumeToken(tok::comma)); + // Diagnose the mix between type args and protocols. + if (foundProtocolId && foundValidTypeId) + Actions.DiagnoseTypeArgsAndProtocols(foundProtocolId, foundProtocolSrcLoc, + foundValidTypeId, + foundValidTypeSrcLoc); + + // Diagnose unknown arg types. + ParsedType T; + if (unknownTypeArgs.size()) + for (unsigned i = 0, e = unknownTypeArgsLoc.size(); i < e; ++i) + Actions.DiagnoseUnknownTypeName(unknownTypeArgs[i], unknownTypeArgsLoc[i], + getCurScope(), nullptr, T); + // Parse the closing '>'. SourceLocation rAngleLoc; (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken, @@ -1976,7 +2004,6 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, } HelperActionsForIvarDeclarations(interfaceDecl, atLoc, T, AllIvarDecls, false); - return; } /// objc-protocol-declaration: @@ -2005,14 +2032,14 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCProtocolDecl(getCurScope()); cutOffParsing(); - return DeclGroupPtrTy(); + return nullptr; } MaybeSkipAttributes(tok::objc_protocol); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; // missing protocol name. - return DeclGroupPtrTy(); + return nullptr; } // Save the protocol name, then consume it. IdentifierInfo *protocolName = Tok.getIdentifierInfo(); @@ -2036,7 +2063,7 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; SkipUntil(tok::semi); - return DeclGroupPtrTy(); + return nullptr; } ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(), Tok.getLocation())); @@ -2047,7 +2074,7 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, } // Consume the ';'. if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@protocol")) - return DeclGroupPtrTy(); + return nullptr; return Actions.ActOnForwardProtocolDeclaration(AtLoc, ProtocolRefs, attrs.getList()); @@ -2062,7 +2089,7 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true, LAngleLoc, EndProtoLoc, /*consumeLastToken=*/true)) - return DeclGroupPtrTy(); + return nullptr; Decl *ProtoType = Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc, @@ -2096,7 +2123,7 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCImplementationDecl(getCurScope()); cutOffParsing(); - return DeclGroupPtrTy(); + return nullptr; } MaybeSkipAttributes(tok::objc_implementation); @@ -2104,7 +2131,7 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; // missing class or category name. - return DeclGroupPtrTy(); + return nullptr; } // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); @@ -2137,7 +2164,7 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc); cutOffParsing(); - return DeclGroupPtrTy(); + return nullptr; } if (Tok.is(tok::identifier)) { @@ -2146,12 +2173,12 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { } else { Diag(Tok, diag::err_expected) << tok::identifier; // missing category name. - return DeclGroupPtrTy(); + return nullptr; } if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected) << tok::r_paren; SkipUntil(tok::r_paren); // don't stop at ';' - return DeclGroupPtrTy(); + return nullptr; } rparenLoc = ConsumeParen(); if (Tok.is(tok::less)) { // we have illegal '<' try to recover @@ -2178,7 +2205,7 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; // missing super class name. - return DeclGroupPtrTy(); + return nullptr; } superClassId = Tok.getIdentifierInfo(); superClassLoc = ConsumeToken(); // Consume super class name @@ -2232,7 +2259,7 @@ Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { else // missing @implementation Diag(atEnd.getBegin(), diag::err_expected_objc_container); - return DeclGroupPtrTy(); + return nullptr; } Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() { @@ -2345,8 +2372,10 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { propertyIvar = Tok.getIdentifierInfo(); propertyIvarLoc = ConsumeToken(); // consume ivar-name } - Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, true, - propertyId, propertyIvar, propertyIvarLoc); + Actions.ActOnPropertyImplDecl( + getCurScope(), atLoc, propertyLoc, true, + propertyId, propertyIvar, propertyIvarLoc, + ObjCPropertyQueryKind::OBJC_PR_query_unknown); if (Tok.isNot(tok::comma)) break; ConsumeToken(); // consume ',' @@ -2366,6 +2395,31 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { assert(Tok.isObjCAtKeyword(tok::objc_dynamic) && "ParseObjCPropertyDynamic(): Expected '@dynamic'"); ConsumeToken(); // consume dynamic + + bool isClassProperty = false; + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + const IdentifierInfo *II = Tok.getIdentifierInfo(); + + if (!II) { + Diag(Tok, diag::err_objc_expected_property_attr) << II; + SkipUntil(tok::r_paren, StopAtSemi); + } else { + SourceLocation AttrName = ConsumeToken(); // consume attribute name + if (II->isStr("class")) { + isClassProperty = true; + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected) << tok::r_paren; + SkipUntil(tok::r_paren, StopAtSemi); + } else + ConsumeParen(); + } else { + Diag(AttrName, diag::err_objc_expected_property_attr) << II; + SkipUntil(tok::r_paren, StopAtSemi); + } + } + } + while (true) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCPropertyDefinition(getCurScope()); @@ -2381,8 +2435,11 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { IdentifierInfo *propertyId = Tok.getIdentifierInfo(); SourceLocation propertyLoc = ConsumeToken(); // consume property name - Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, false, - propertyId, nullptr, SourceLocation()); + Actions.ActOnPropertyImplDecl( + getCurScope(), atLoc, propertyLoc, false, + propertyId, nullptr, SourceLocation(), + isClassProperty ? ObjCPropertyQueryKind::OBJC_PR_query_class : + ObjCPropertyQueryKind::OBJC_PR_query_unknown); if (Tok.isNot(tok::comma)) break; @@ -2599,6 +2656,12 @@ Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) { /// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them /// for later parsing. void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) { + if (SkipFunctionBodies && (!MDecl || Actions.canSkipFunctionBody(MDecl)) && + trySkippingFunctionBody()) { + Actions.ActOnSkippedFunctionBody(MDecl); + return; + } + LexedMethod* LM = new LexedMethod(this, MDecl); CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM); CachedTokens &Toks = LM->Toks; @@ -2795,6 +2858,8 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc)); case tok::objc_selector: return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc)); + case tok::objc_available: + return ParseAvailabilityCheckExpr(AtLoc); default: { const char *str = nullptr; if (GetLookAheadToken(1).is(tok::l_brace)) { @@ -2923,7 +2988,6 @@ bool Parser::isStartOfObjCClassMessageMissingOpenBracket() { InMessageExpression) return false; - ParsedType Type; if (Tok.is(tok::annot_typename)) @@ -2977,8 +3041,8 @@ ExprResult Parser::ParseObjCMessageExpression() { // get in Objective-C. if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super && NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope()) - return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), - ParsedType(), nullptr); + return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr, + nullptr); // Parse the receiver, which is either a type or an expression. bool IsExpr; @@ -2989,9 +3053,8 @@ ExprResult Parser::ParseObjCMessageExpression() { } if (IsExpr) - return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), - ParsedType(), - static_cast<Expr*>(TypeOrExpr)); + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr, + static_cast<Expr *>(TypeOrExpr)); return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), ParsedType::getFromOpaquePtr(TypeOrExpr), @@ -3007,8 +3070,8 @@ ExprResult Parser::ParseObjCMessageExpression() { NextToken().is(tok::period), ReceiverType)) { case Sema::ObjCSuperMessage: - return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), - ParsedType(), nullptr); + return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), nullptr, + nullptr); case Sema::ObjCClassMessage: if (!ReceiverType) { @@ -3049,8 +3112,8 @@ ExprResult Parser::ParseObjCMessageExpression() { return Res; } - return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), - ParsedType(), Res.get()); + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), nullptr, + Res.get()); } /// \brief Parse the remainder of an Objective-C message following the @@ -3553,7 +3616,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { T.getOpenLocation(), T.getCloseLocation(), !HasOptionalParen); - } +} void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { // MCDecl might be null due to error in method or c-function prototype, etc. @@ -3571,8 +3634,8 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { // Append the current token at the end of the new token stream so that it // doesn't get lost. LM.Toks.push_back(Tok); - PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); - + PP.EnterTokenStream(LM.Toks, true); + // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); @@ -3595,6 +3658,8 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { else { if (Tok.is(tok::colon)) ParseConstructorInitializer(MCDecl); + else + Actions.ActOnDefaultCtorInitializers(MCDecl); ParseFunctionStatementBody(MCDecl, BodyScope); } @@ -3609,6 +3674,4 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); } - - return; } diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index a08db5490fa9..df7d9bc0d8c8 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -26,78 +26,537 @@ using namespace clang; // OpenMP declarative directives. //===----------------------------------------------------------------------===// +namespace { +enum OpenMPDirectiveKindEx { + OMPD_cancellation = OMPD_unknown + 1, + OMPD_data, + OMPD_declare, + OMPD_end, + OMPD_end_declare, + OMPD_enter, + OMPD_exit, + OMPD_point, + OMPD_reduction, + OMPD_target_enter, + OMPD_target_exit, + OMPD_update, + OMPD_distribute_parallel +}; + +class ThreadprivateListParserHelper final { + SmallVector<Expr *, 4> Identifiers; + Parser *P; + +public: + ThreadprivateListParserHelper(Parser *P) : P(P) {} + void operator()(CXXScopeSpec &SS, DeclarationNameInfo NameInfo) { + ExprResult Res = + P->getActions().ActOnOpenMPIdExpression(P->getCurScope(), SS, NameInfo); + if (Res.isUsable()) + Identifiers.push_back(Res.get()); + } + llvm::ArrayRef<Expr *> getIdentifiers() const { return Identifiers; } +}; +} // namespace + +// Map token string to extended OMP token kind that are +// OpenMPDirectiveKind + OpenMPDirectiveKindEx. +static unsigned getOpenMPDirectiveKindEx(StringRef S) { + auto DKind = getOpenMPDirectiveKind(S); + if (DKind != OMPD_unknown) + return DKind; + + return llvm::StringSwitch<unsigned>(S) + .Case("cancellation", OMPD_cancellation) + .Case("data", OMPD_data) + .Case("declare", OMPD_declare) + .Case("end", OMPD_end) + .Case("enter", OMPD_enter) + .Case("exit", OMPD_exit) + .Case("point", OMPD_point) + .Case("reduction", OMPD_reduction) + .Case("update", OMPD_update) + .Default(OMPD_unknown); +} + static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) { // Array of foldings: F[i][0] F[i][1] ===> F[i][2]. // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd // TODO: add other combined directives in topological order. - const OpenMPDirectiveKind F[][3] = { - {OMPD_unknown /*cancellation*/, OMPD_unknown /*point*/, - OMPD_cancellation_point}, - {OMPD_target, OMPD_unknown /*data*/, OMPD_target_data}, - {OMPD_for, OMPD_simd, OMPD_for_simd}, - {OMPD_parallel, OMPD_for, OMPD_parallel_for}, - {OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd}, - {OMPD_parallel, OMPD_sections, OMPD_parallel_sections}, - {OMPD_taskloop, OMPD_simd, OMPD_taskloop_simd}}; + static const unsigned F[][3] = { + { OMPD_cancellation, OMPD_point, OMPD_cancellation_point }, + { OMPD_declare, OMPD_reduction, OMPD_declare_reduction }, + { OMPD_declare, OMPD_simd, OMPD_declare_simd }, + { OMPD_declare, OMPD_target, OMPD_declare_target }, + { OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel }, + { OMPD_distribute_parallel, OMPD_for, OMPD_distribute_parallel_for }, + { OMPD_distribute_parallel_for, OMPD_simd, + OMPD_distribute_parallel_for_simd }, + { OMPD_distribute, OMPD_simd, OMPD_distribute_simd }, + { OMPD_end, OMPD_declare, OMPD_end_declare }, + { OMPD_end_declare, OMPD_target, OMPD_end_declare_target }, + { OMPD_target, OMPD_data, OMPD_target_data }, + { OMPD_target, OMPD_enter, OMPD_target_enter }, + { OMPD_target, OMPD_exit, OMPD_target_exit }, + { OMPD_target, OMPD_update, OMPD_target_update }, + { OMPD_target_enter, OMPD_data, OMPD_target_enter_data }, + { OMPD_target_exit, OMPD_data, OMPD_target_exit_data }, + { OMPD_for, OMPD_simd, OMPD_for_simd }, + { OMPD_parallel, OMPD_for, OMPD_parallel_for }, + { OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd }, + { OMPD_parallel, OMPD_sections, OMPD_parallel_sections }, + { OMPD_taskloop, OMPD_simd, OMPD_taskloop_simd }, + { OMPD_target, OMPD_parallel, OMPD_target_parallel }, + { OMPD_target_parallel, OMPD_for, OMPD_target_parallel_for }, + { OMPD_target_parallel_for, OMPD_simd, OMPD_target_parallel_for_simd } + }; + enum { CancellationPoint = 0, DeclareReduction = 1, TargetData = 2 }; auto Tok = P.getCurToken(); - auto DKind = + unsigned DKind = Tok.isAnnotation() - ? OMPD_unknown - : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok)); + ? static_cast<unsigned>(OMPD_unknown) + : getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok)); + if (DKind == OMPD_unknown) + return OMPD_unknown; - bool TokenMatched = false; for (unsigned i = 0; i < llvm::array_lengthof(F); ++i) { - if (!Tok.isAnnotation() && DKind == OMPD_unknown) { - TokenMatched = - (i == 0) && - !P.getPreprocessor().getSpelling(Tok).compare("cancellation"); + if (DKind != F[i][0]) + continue; + + Tok = P.getPreprocessor().LookAhead(0); + unsigned SDKind = + Tok.isAnnotation() + ? static_cast<unsigned>(OMPD_unknown) + : getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok)); + if (SDKind == OMPD_unknown) + continue; + + if (SDKind == F[i][1]) { + P.ConsumeToken(); + DKind = F[i][2]; + } + } + return DKind < OMPD_unknown ? static_cast<OpenMPDirectiveKind>(DKind) + : OMPD_unknown; +} + +static DeclarationName parseOpenMPReductionId(Parser &P) { + Token Tok = P.getCurToken(); + Sema &Actions = P.getActions(); + OverloadedOperatorKind OOK = OO_None; + // Allow to use 'operator' keyword for C++ operators + bool WithOperator = false; + if (Tok.is(tok::kw_operator)) { + P.ConsumeToken(); + Tok = P.getCurToken(); + WithOperator = true; + } + switch (Tok.getKind()) { + case tok::plus: // '+' + OOK = OO_Plus; + break; + case tok::minus: // '-' + OOK = OO_Minus; + break; + case tok::star: // '*' + OOK = OO_Star; + break; + case tok::amp: // '&' + OOK = OO_Amp; + break; + case tok::pipe: // '|' + OOK = OO_Pipe; + break; + case tok::caret: // '^' + OOK = OO_Caret; + break; + case tok::ampamp: // '&&' + OOK = OO_AmpAmp; + break; + case tok::pipepipe: // '||' + OOK = OO_PipePipe; + break; + case tok::identifier: // identifier + if (!WithOperator) + break; + default: + P.Diag(Tok.getLocation(), diag::err_omp_expected_reduction_identifier); + P.SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + Parser::StopBeforeMatch); + return DeclarationName(); + } + P.ConsumeToken(); + auto &DeclNames = Actions.getASTContext().DeclarationNames; + return OOK == OO_None ? DeclNames.getIdentifier(Tok.getIdentifierInfo()) + : DeclNames.getCXXOperatorName(OOK); +} + +/// \brief Parse 'omp declare reduction' construct. +/// +/// declare-reduction-directive: +/// annot_pragma_openmp 'declare' 'reduction' +/// '(' <reduction_id> ':' <type> {',' <type>} ':' <expression> ')' +/// ['initializer' '(' ('omp_priv' '=' <expression>)|<function_call> ')'] +/// annot_pragma_openmp_end +/// <reduction_id> is either a base language identifier or one of the following +/// operators: '+', '-', '*', '&', '|', '^', '&&' and '||'. +/// +Parser::DeclGroupPtrTy +Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPDirectiveName(OMPD_declare_reduction))) { + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + return DeclGroupPtrTy(); + } + + DeclarationName Name = parseOpenMPReductionId(*this); + if (Name.isEmpty() && Tok.is(tok::annot_pragma_openmp_end)) + return DeclGroupPtrTy(); + + // Consume ':'. + bool IsCorrect = !ExpectAndConsume(tok::colon); + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return DeclGroupPtrTy(); + + IsCorrect = IsCorrect && !Name.isEmpty(); + + if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_expected_type); + IsCorrect = false; + } + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return DeclGroupPtrTy(); + + SmallVector<std::pair<QualType, SourceLocation>, 8> ReductionTypes; + // Parse list of types until ':' token. + do { + ColonProtectionRAIIObject ColonRAII(*this); + SourceRange Range; + TypeResult TR = ParseTypeName(&Range, Declarator::PrototypeContext, AS); + if (TR.isUsable()) { + auto ReductionType = + Actions.ActOnOpenMPDeclareReductionType(Range.getBegin(), TR); + if (!ReductionType.isNull()) { + ReductionTypes.push_back( + std::make_pair(ReductionType, Range.getBegin())); + } } else { - TokenMatched = DKind == F[i][0] && DKind != OMPD_unknown; + SkipUntil(tok::comma, tok::colon, tok::annot_pragma_openmp_end, + StopBeforeMatch); } - if (TokenMatched) { - Tok = P.getPreprocessor().LookAhead(0); - auto TokenIsAnnotation = Tok.isAnnotation(); - auto SDKind = - TokenIsAnnotation - ? OMPD_unknown - : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok)); - - if (!TokenIsAnnotation && SDKind == OMPD_unknown) { - TokenMatched = - ((i == 0) && - !P.getPreprocessor().getSpelling(Tok).compare("point")) || - ((i == 1) && !P.getPreprocessor().getSpelling(Tok).compare("data")); - } else { - TokenMatched = SDKind == F[i][1] && SDKind != OMPD_unknown; + if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) + break; + + // Consume ','. + if (ExpectAndConsume(tok::comma)) { + IsCorrect = false; + if (Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_expected_type); + return DeclGroupPtrTy(); } + } + } while (Tok.isNot(tok::annot_pragma_openmp_end)); - if (TokenMatched) { - P.ConsumeToken(); - DKind = F[i][2]; + if (ReductionTypes.empty()) { + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + return DeclGroupPtrTy(); + } + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return DeclGroupPtrTy(); + + // Consume ':'. + if (ExpectAndConsume(tok::colon)) + IsCorrect = false; + + if (Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_expected_expression); + return DeclGroupPtrTy(); + } + + DeclGroupPtrTy DRD = Actions.ActOnOpenMPDeclareReductionDirectiveStart( + getCurScope(), Actions.getCurLexicalContext(), Name, ReductionTypes, AS); + + // Parse <combiner> expression and then parse initializer if any for each + // correct type. + unsigned I = 0, E = ReductionTypes.size(); + for (auto *D : DRD.get()) { + TentativeParsingAction TPA(*this); + ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope | + Scope::OpenMPDirectiveScope); + // Parse <combiner> expression. + Actions.ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D); + ExprResult CombinerResult = + Actions.ActOnFinishFullExpr(ParseAssignmentExpression().get(), + D->getLocation(), /*DiscardedValue=*/true); + Actions.ActOnOpenMPDeclareReductionCombinerEnd(D, CombinerResult.get()); + + if (CombinerResult.isInvalid() && Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { + TPA.Commit(); + IsCorrect = false; + break; + } + IsCorrect = !T.consumeClose() && IsCorrect && CombinerResult.isUsable(); + ExprResult InitializerResult; + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + // Parse <initializer> expression. + if (Tok.is(tok::identifier) && + Tok.getIdentifierInfo()->isStr("initializer")) + ConsumeToken(); + else { + Diag(Tok.getLocation(), diag::err_expected) << "'initializer'"; + TPA.Commit(); + IsCorrect = false; + break; + } + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + IsCorrect = + !T.expectAndConsume(diag::err_expected_lparen_after, "initializer") && + IsCorrect; + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope | + Scope::OpenMPDirectiveScope); + // Parse expression. + Actions.ActOnOpenMPDeclareReductionInitializerStart(getCurScope(), D); + InitializerResult = Actions.ActOnFinishFullExpr( + ParseAssignmentExpression().get(), D->getLocation(), + /*DiscardedValue=*/true); + Actions.ActOnOpenMPDeclareReductionInitializerEnd( + D, InitializerResult.get()); + if (InitializerResult.isInvalid() && Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { + TPA.Commit(); + IsCorrect = false; + break; + } + IsCorrect = + !T.consumeClose() && IsCorrect && !InitializerResult.isInvalid(); } } + + ++I; + // Revert parsing if not the last type, otherwise accept it, we're done with + // parsing. + if (I != E) + TPA.Revert(); + else + TPA.Commit(); } - return DKind; + return Actions.ActOnOpenMPDeclareReductionDirectiveEnd(getCurScope(), DRD, + IsCorrect); +} + +namespace { +/// RAII that recreates function context for correct parsing of clauses of +/// 'declare simd' construct. +/// OpenMP, 2.8.2 declare simd Construct +/// The expressions appearing in the clauses of this directive are evaluated in +/// the scope of the arguments of the function declaration or definition. +class FNContextRAII final { + Parser &P; + Sema::CXXThisScopeRAII *ThisScope; + Parser::ParseScope *TempScope; + Parser::ParseScope *FnScope; + bool HasTemplateScope = false; + bool HasFunScope = false; + FNContextRAII() = delete; + FNContextRAII(const FNContextRAII &) = delete; + FNContextRAII &operator=(const FNContextRAII &) = delete; + +public: + FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr) : P(P) { + Decl *D = *Ptr.get().begin(); + NamedDecl *ND = dyn_cast<NamedDecl>(D); + RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext()); + Sema &Actions = P.getActions(); + + // Allow 'this' within late-parsed attributes. + ThisScope = new Sema::CXXThisScopeRAII(Actions, RD, /*TypeQuals=*/0, + ND && ND->isCXXInstanceMember()); + + // If the Decl is templatized, add template parameters to scope. + HasTemplateScope = D->isTemplateDecl(); + TempScope = + new Parser::ParseScope(&P, Scope::TemplateParamScope, HasTemplateScope); + if (HasTemplateScope) + Actions.ActOnReenterTemplateScope(Actions.getCurScope(), D); + + // If the Decl is on a function, add function parameters to the scope. + HasFunScope = D->isFunctionOrFunctionTemplate(); + FnScope = new Parser::ParseScope(&P, Scope::FnScope | Scope::DeclScope, + HasFunScope); + if (HasFunScope) + Actions.ActOnReenterFunctionContext(Actions.getCurScope(), D); + } + ~FNContextRAII() { + if (HasFunScope) { + P.getActions().ActOnExitFunctionContext(); + FnScope->Exit(); // Pop scope, and remove Decls from IdResolver + } + if (HasTemplateScope) + TempScope->Exit(); + delete FnScope; + delete TempScope; + delete ThisScope; + } +}; +} // namespace + +/// Parses clauses for 'declare simd' directive. +/// clause: +/// 'inbranch' | 'notinbranch' +/// 'simdlen' '(' <expr> ')' +/// { 'uniform' '(' <argument_list> ')' } +/// { 'aligned '(' <argument_list> [ ':' <alignment> ] ')' } +/// { 'linear '(' <argument_list> [ ':' <step> ] ')' } +static bool parseDeclareSimdClauses( + Parser &P, OMPDeclareSimdDeclAttr::BranchStateTy &BS, ExprResult &SimdLen, + SmallVectorImpl<Expr *> &Uniforms, SmallVectorImpl<Expr *> &Aligneds, + SmallVectorImpl<Expr *> &Alignments, SmallVectorImpl<Expr *> &Linears, + SmallVectorImpl<unsigned> &LinModifiers, SmallVectorImpl<Expr *> &Steps) { + SourceRange BSRange; + const Token &Tok = P.getCurToken(); + bool IsError = false; + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + if (Tok.isNot(tok::identifier)) + break; + OMPDeclareSimdDeclAttr::BranchStateTy Out; + IdentifierInfo *II = Tok.getIdentifierInfo(); + StringRef ClauseName = II->getName(); + // Parse 'inranch|notinbranch' clauses. + if (OMPDeclareSimdDeclAttr::ConvertStrToBranchStateTy(ClauseName, Out)) { + if (BS != OMPDeclareSimdDeclAttr::BS_Undefined && BS != Out) { + P.Diag(Tok, diag::err_omp_declare_simd_inbranch_notinbranch) + << ClauseName + << OMPDeclareSimdDeclAttr::ConvertBranchStateTyToStr(BS) << BSRange; + IsError = true; + } + BS = Out; + BSRange = SourceRange(Tok.getLocation(), Tok.getEndLoc()); + P.ConsumeToken(); + } else if (ClauseName.equals("simdlen")) { + if (SimdLen.isUsable()) { + P.Diag(Tok, diag::err_omp_more_one_clause) + << getOpenMPDirectiveName(OMPD_declare_simd) << ClauseName << 0; + IsError = true; + } + P.ConsumeToken(); + SourceLocation RLoc; + SimdLen = P.ParseOpenMPParensExpr(ClauseName, RLoc); + if (SimdLen.isInvalid()) + IsError = true; + } else { + OpenMPClauseKind CKind = getOpenMPClauseKind(ClauseName); + if (CKind == OMPC_uniform || CKind == OMPC_aligned || + CKind == OMPC_linear) { + Parser::OpenMPVarListDataTy Data; + auto *Vars = &Uniforms; + if (CKind == OMPC_aligned) + Vars = &Aligneds; + else if (CKind == OMPC_linear) + Vars = &Linears; + + P.ConsumeToken(); + if (P.ParseOpenMPVarList(OMPD_declare_simd, + getOpenMPClauseKind(ClauseName), *Vars, Data)) + IsError = true; + if (CKind == OMPC_aligned) + Alignments.append(Aligneds.size() - Alignments.size(), Data.TailExpr); + else if (CKind == OMPC_linear) { + if (P.getActions().CheckOpenMPLinearModifier(Data.LinKind, + Data.DepLinMapLoc)) + Data.LinKind = OMPC_LINEAR_val; + LinModifiers.append(Linears.size() - LinModifiers.size(), + Data.LinKind); + Steps.append(Linears.size() - Steps.size(), Data.TailExpr); + } + } else + // TODO: add parsing of other clauses. + break; + } + // Skip ',' if any. + if (Tok.is(tok::comma)) + P.ConsumeToken(); + } + return IsError; +} + +/// Parse clauses for '#pragma omp declare simd'. +Parser::DeclGroupPtrTy +Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr, + CachedTokens &Toks, SourceLocation Loc) { + PP.EnterToken(Tok); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); + // Consume the previously pushed token. + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); + + FNContextRAII FnContext(*this, Ptr); + OMPDeclareSimdDeclAttr::BranchStateTy BS = + OMPDeclareSimdDeclAttr::BS_Undefined; + ExprResult Simdlen; + SmallVector<Expr *, 4> Uniforms; + SmallVector<Expr *, 4> Aligneds; + SmallVector<Expr *, 4> Alignments; + SmallVector<Expr *, 4> Linears; + SmallVector<unsigned, 4> LinModifiers; + SmallVector<Expr *, 4> Steps; + bool IsError = + parseDeclareSimdClauses(*this, BS, Simdlen, Uniforms, Aligneds, + Alignments, Linears, LinModifiers, Steps); + // Need to check for extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_simd); + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + } + // Skip the last annot_pragma_openmp_end. + SourceLocation EndLoc = ConsumeToken(); + if (!IsError) { + return Actions.ActOnOpenMPDeclareSimdDirective( + Ptr, BS, Simdlen.get(), Uniforms, Aligneds, Alignments, Linears, + LinModifiers, Steps, SourceRange(Loc, EndLoc)); + } + return Ptr; } /// \brief Parsing of declarative OpenMP directives. /// /// threadprivate-directive: /// annot_pragma_openmp 'threadprivate' simple-variable-list +/// annot_pragma_openmp_end +/// +/// declare-reduction-directive: +/// annot_pragma_openmp 'declare' 'reduction' [...] +/// annot_pragma_openmp_end +/// +/// declare-simd-directive: +/// annot_pragma_openmp 'declare simd' {<clause> [,]} +/// annot_pragma_openmp_end +/// <function declaration/definition> /// -Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { +Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( + AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, + DeclSpec::TST TagType, Decl *Tag) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); ParenBraceBracketBalancer BalancerRAIIObj(*this); SourceLocation Loc = ConsumeToken(); - SmallVector<Expr *, 5> Identifiers; auto DKind = ParseOpenMPDirectiveKind(*this); switch (DKind) { - case OMPD_threadprivate: + case OMPD_threadprivate: { ConsumeToken(); - if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) { + ThreadprivateListParserHelper Helper(this); + if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Helper, true)) { // The last seen token is annot_pragma_openmp_end - need to check for // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { @@ -107,9 +566,140 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { } // Skip the last annot_pragma_openmp_end. ConsumeToken(); - return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers); + return Actions.ActOnOpenMPThreadprivateDirective(Loc, + Helper.getIdentifiers()); + } + break; + } + case OMPD_declare_reduction: + ConsumeToken(); + if (auto Res = ParseOpenMPDeclareReductionDirective(AS)) { + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_reduction); + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + } + // Skip the last annot_pragma_openmp_end. + ConsumeToken(); + return Res; } break; + case OMPD_declare_simd: { + // The syntax is: + // { #pragma omp declare simd } + // <function-declaration-or-definition> + // + ConsumeToken(); + CachedTokens Toks; + while(Tok.isNot(tok::annot_pragma_openmp_end)) { + Toks.push_back(Tok); + ConsumeAnyToken(); + } + Toks.push_back(Tok); + ConsumeAnyToken(); + + DeclGroupPtrTy Ptr; + if (Tok.is(tok::annot_pragma_openmp)) + Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, TagType, Tag); + else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) { + // Here we expect to see some function declaration. + if (AS == AS_none) { + assert(TagType == DeclSpec::TST_unspecified); + MaybeParseCXX11Attributes(Attrs); + MaybeParseMicrosoftAttributes(Attrs); + ParsingDeclSpec PDS(*this); + Ptr = ParseExternalDeclaration(Attrs, &PDS); + } else { + Ptr = + ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag); + } + } + if (!Ptr) { + Diag(Loc, diag::err_omp_decl_in_declare_simd); + return DeclGroupPtrTy(); + } + return ParseOMPDeclareSimdClauses(Ptr, Toks, Loc); + } + case OMPD_declare_target: { + SourceLocation DTLoc = ConsumeAnyToken(); + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + // OpenMP 4.5 syntax with list of entities. + llvm::SmallSetVector<const NamedDecl*, 16> SameDirectiveDecls; + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OMPDeclareTargetDeclAttr::MapTypeTy MT = + OMPDeclareTargetDeclAttr::MT_To; + if (Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + StringRef ClauseName = II->getName(); + // Parse 'to|link' clauses. + if (!OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, + MT)) { + Diag(Tok, diag::err_omp_declare_target_unexpected_clause) + << ClauseName; + break; + } + ConsumeToken(); + } + auto Callback = [this, MT, &SameDirectiveDecls]( + CXXScopeSpec &SS, DeclarationNameInfo NameInfo) { + Actions.ActOnOpenMPDeclareTargetName(getCurScope(), SS, NameInfo, MT, + SameDirectiveDecls); + }; + if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback, true)) + break; + + // Consume optional ','. + if (Tok.is(tok::comma)) + ConsumeToken(); + } + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + ConsumeAnyToken(); + return DeclGroupPtrTy(); + } + + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + + if (!Actions.ActOnStartOpenMPDeclareTargetDirective(DTLoc)) + return DeclGroupPtrTy(); + + DKind = ParseOpenMPDirectiveKind(*this); + while (DKind != OMPD_end_declare_target && DKind != OMPD_declare_target && + Tok.isNot(tok::eof) && Tok.isNot(tok::r_brace)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX11Attributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + ParseExternalDeclaration(attrs); + if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) { + TentativeParsingAction TPA(*this); + ConsumeToken(); + DKind = ParseOpenMPDirectiveKind(*this); + if (DKind != OMPD_end_declare_target) + TPA.Revert(); + else + TPA.Commit(); + } + } + + if (DKind == OMPD_end_declare_target) { + ConsumeAnyToken(); + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_end_declare_target); + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + } + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + } else { + Diag(Tok, diag::err_expected_end_declare_target); + Diag(DTLoc, diag::note_matching) << "'#pragma omp declare target'"; + } + Actions.ActOnFinishOpenMPDeclareTargetDirective(); + return DeclGroupPtrTy(); + } case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; @@ -138,15 +728,27 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { case OMPD_cancellation_point: case OMPD_cancel: case OMPD_target_data: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target_parallel: + case OMPD_target_parallel_for: case OMPD_taskloop: case OMPD_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: + case OMPD_distribute_simd: + case OMPD_target_parallel_for_simd: Diag(Tok, diag::err_omp_unexpected_directive) << getOpenMPDirectiveName(DKind); break; } - SkipUntil(tok::annot_pragma_openmp_end); - return DeclGroupPtrTy(); + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + ConsumeAnyToken(); + return nullptr; } /// \brief Parsing of declarative or executable OpenMP directives. @@ -155,21 +757,30 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { /// annot_pragma_openmp 'threadprivate' simple-variable-list /// annot_pragma_openmp_end /// +/// declare-reduction-directive: +/// annot_pragma_openmp 'declare' 'reduction' '(' <reduction_id> ':' +/// <type> {',' <type>} ':' <expression> ')' ['initializer' '(' +/// ('omp_priv' '=' <expression>|<function_call>) ')'] +/// annot_pragma_openmp_end +/// /// executable-directive: /// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' | /// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] | /// 'parallel for' | 'parallel sections' | 'task' | 'taskyield' | /// 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'atomic' | /// 'for simd' | 'parallel for simd' | 'target' | 'target data' | -/// 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' {clause} | -/// 'distribute' +/// 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' | +/// 'distribute' | 'target enter data' | 'target exit data' | +/// 'target parallel' | 'target parallel for' | +/// 'target update' | 'distribute parallel for' | +/// 'distribute paralle for simd' | 'distribute simd' | +/// 'target parallel for simd' {clause} /// annot_pragma_openmp_end /// StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( AllowedContsructsKind Allowed) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); ParenBraceBracketBalancer BalancerRAIIObj(*this); - SmallVector<Expr *, 5> Identifiers; SmallVector<OMPClause *, 5> Clauses; SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1> FirstClauses(OMPC_unknown + 1); @@ -185,13 +796,14 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( bool FlushHasClause = false; switch (DKind) { - case OMPD_threadprivate: + case OMPD_threadprivate: { if (Allowed != ACK_Any) { Diag(Tok, diag::err_omp_immediate_directive) << getOpenMPDirectiveName(DKind) << 0; } ConsumeToken(); - if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) { + ThreadprivateListParserHelper Helper(this); + if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Helper, false)) { // The last seen token is annot_pragma_openmp_end - need to check for // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { @@ -199,12 +811,29 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( << getOpenMPDirectiveName(OMPD_threadprivate); SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); } - DeclGroupPtrTy Res = - Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers); + DeclGroupPtrTy Res = Actions.ActOnOpenMPThreadprivateDirective( + Loc, Helper.getIdentifiers()); Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); } SkipUntil(tok::annot_pragma_openmp_end); break; + } + case OMPD_declare_reduction: + ConsumeToken(); + if (auto Res = ParseOpenMPDeclareReductionDirective(/*AS=*/AS_none)) { + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_reduction); + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + } + ConsumeAnyToken(); + Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); + } else + SkipUntil(tok::annot_pragma_openmp_end); + break; case OMPD_flush: if (PP.LookAhead(0).is(tok::l_paren)) { FlushHasClause = true; @@ -217,6 +846,9 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_cancel: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target_update: if (Allowed == ACK_StatementsOpenMPNonStandalone) { Diag(Tok, diag::err_omp_immediate_directive) << getOpenMPDirectiveName(DKind) << 0; @@ -242,9 +874,15 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( case OMPD_teams: case OMPD_taskgroup: case OMPD_target_data: + case OMPD_target_parallel: + case OMPD_target_parallel_for: case OMPD_taskloop: case OMPD_taskloop_simd: - case OMPD_distribute: { + case OMPD_distribute: + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + case OMPD_distribute_simd: + case OMPD_target_parallel_for_simd: { ConsumeToken(); // Parse directive name of the 'critical' directive if any. if (DKind == OMPD_critical) { @@ -331,6 +969,13 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( OMPDirectiveScope.Exit(); break; } + case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: + Diag(Tok, diag::err_omp_unexpected_directive) + << getOpenMPDirectiveName(DKind); + SkipUntil(tok::annot_pragma_openmp_end); + break; case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); SkipUntil(tok::annot_pragma_openmp_end); @@ -339,16 +984,15 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( return Directive; } -/// \brief Parses list of simple variables for '#pragma omp threadprivate' -/// directive. -/// -/// simple-variable-list: -/// '(' id-expression {, id-expression} ')' -/// -bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, - SmallVectorImpl<Expr *> &VarList, - bool AllowScopeSpecifier) { - VarList.clear(); +// Parses simple list: +// simple-variable-list: +// '(' id-expression {, id-expression} ')' +// +bool Parser::ParseOpenMPSimpleVarList( + OpenMPDirectiveKind Kind, + const llvm::function_ref<void(CXXScopeSpec &, DeclarationNameInfo)> & + Callback, + bool AllowScopeSpecifier) { // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, @@ -367,11 +1011,11 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, NoIdentIsFound = false; if (AllowScopeSpecifier && getLangOpts().CPlusPlus && - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) { + ParseOptionalCXXScopeSpecifier(SS, nullptr, false)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); - } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(), + } else if (ParseUnqualifiedId(SS, false, false, false, nullptr, TemplateKWLoc, Name)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, @@ -385,11 +1029,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, << tok::identifier << SourceRange(PrevTok.getLocation(), PrevTokLocation); } else { - DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name); - ExprResult Res = - Actions.ActOnOpenMPIdExpression(getCurScope(), SS, NameInfo); - if (Res.isUsable()) - VarList.push_back(Res.get()); + Callback(SS, Actions.GetNameFromUnqualifiedId(Name)); } // Consume ','. if (Tok.is(tok::comma)) { @@ -405,7 +1045,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, // Parse ')'. IsCorrect = !T.consumeClose() && IsCorrect; - return !IsCorrect && VarList.empty(); + return !IsCorrect; } /// \brief Parsing of OpenMP clauses. @@ -420,7 +1060,8 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, /// update-clause | capture-clause | seq_cst-clause | device-clause | /// simdlen-clause | threads-clause | simd-clause | num_teams-clause | /// thread_limit-clause | priority-clause | grainsize-clause | -/// nogroup-clause | num_tasks-clause | hint-clause +/// nogroup-clause | num_tasks-clause | hint-clause | to-clause | +/// from-clause | is_device_ptr-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { @@ -494,8 +1135,12 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, Clause = ParseOpenMPSimpleClause(CKind); break; case OMPC_schedule: + case OMPC_dist_schedule: + case OMPC_defaultmap: // OpenMP [2.7.1, Restrictions, p. 3] // Only one schedule clause can appear on a loop directive. + // OpenMP [2.10.4, Restrictions, p. 106] + // At most one defaultmap clause can appear on the directive. if (!FirstClause) { Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0; @@ -540,6 +1185,10 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_flush: case OMPC_depend: case OMPC_map: + case OMPC_to: + case OMPC_from: + case OMPC_use_device_ptr: + case OMPC_is_device_ptr: Clause = ParseOpenMPVarListClause(DKind, CKind); break; case OMPC_unknown: @@ -548,6 +1197,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); break; case OMPC_threadprivate: + case OMPC_uniform: Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -556,6 +1206,28 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, return ErrorFound ? nullptr : Clause; } +/// Parses simple expression in parens for single-expression clauses of OpenMP +/// constructs. +/// \param RLoc Returned location of right paren. +ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName, + SourceLocation &RLoc) { + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, ClauseName.data())) + return ExprError(); + + SourceLocation ELoc = Tok.getLocation(); + ExprResult LHS(ParseCastExpression( + /*isUnaryExpression=*/false, /*isAddressOfOperand=*/false, NotTypeCast)); + ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc); + + // Parse ')'. + T.consumeClose(); + + RLoc = T.getCloseLocation(); + return Val; +} + /// \brief Parsing of OpenMP clauses with single expressions like 'final', /// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams', /// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks' or 'hint'. @@ -589,25 +1261,15 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, /// OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) { SourceLocation Loc = ConsumeToken(); + SourceLocation LLoc = Tok.getLocation(); + SourceLocation RLoc; - BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); - if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPClauseName(Kind))) - return nullptr; - - SourceLocation ELoc = Tok.getLocation(); - ExprResult LHS(ParseCastExpression(false, false, NotTypeCast)); - ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); - Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc); - - // Parse ')'. - T.consumeClose(); + ExprResult Val = ParseOpenMPParensExpr(getOpenMPClauseName(Kind), RLoc); if (Val.isInvalid()) return nullptr; - return Actions.ActOnOpenMPSingleExprClause( - Kind, Val.get(), Loc, T.getOpenLocation(), T.getCloseLocation()); + return Actions.ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc, LLoc, RLoc); } /// \brief Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. @@ -685,6 +1347,9 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind) { /// if-clause: /// 'if' '(' [ directive-name-modifier ':' ] expression ')' /// +/// defaultmap: +/// 'defaultmap' '(' modifier ':' kind ')' +/// OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind) { SourceLocation Loc = ConsumeToken(); SourceLocation DelimLoc; @@ -744,6 +1409,35 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind) { Arg[ScheduleKind] == OMPC_SCHEDULE_guided) && Tok.is(tok::comma)) DelimLoc = ConsumeAnyToken(); + } else if (Kind == OMPC_dist_schedule) { + Arg.push_back(getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok))); + KLoc.push_back(Tok.getLocation()); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + if (Arg.back() == OMPC_DIST_SCHEDULE_static && Tok.is(tok::comma)) + DelimLoc = ConsumeAnyToken(); + } else if (Kind == OMPC_defaultmap) { + // Get a defaultmap modifier + Arg.push_back(getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok))); + KLoc.push_back(Tok.getLocation()); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + // Parse ':' + if (Tok.is(tok::colon)) + ConsumeAnyToken(); + else if (Arg.back() != OMPC_DEFAULTMAP_MODIFIER_unknown) + Diag(Tok, diag::warn_pragma_expected_colon) << "defaultmap modifier"; + // Get a defaultmap kind + Arg.push_back(getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok))); + KLoc.push_back(Tok.getLocation()); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); } else { assert(Kind == OMPC_if); KLoc.push_back(Tok.getLocation()); @@ -758,8 +1452,9 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind) { } } - bool NeedAnExpression = - (Kind == OMPC_schedule && DelimLoc.isValid()) || Kind == OMPC_if; + bool NeedAnExpression = (Kind == OMPC_schedule && DelimLoc.isValid()) || + (Kind == OMPC_dist_schedule && DelimLoc.isValid()) || + Kind == OMPC_if; if (NeedAnExpression) { SourceLocation ELoc = Tok.getLocation(); ExprResult LHS(ParseCastExpression(false, false, NotTypeCast)); @@ -820,65 +1515,24 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec, } return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false, /*AllowDestructorName*/ false, - /*AllowConstructorName*/ false, ParsedType(), + /*AllowConstructorName*/ false, nullptr, TemplateKWLoc, ReductionId); } -/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate', -/// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'. -/// -/// private-clause: -/// 'private' '(' list ')' -/// firstprivate-clause: -/// 'firstprivate' '(' list ')' -/// lastprivate-clause: -/// 'lastprivate' '(' list ')' -/// shared-clause: -/// 'shared' '(' list ')' -/// linear-clause: -/// 'linear' '(' linear-list [ ':' linear-step ] ')' -/// aligned-clause: -/// 'aligned' '(' list [ ':' alignment ] ')' -/// reduction-clause: -/// 'reduction' '(' reduction-identifier ':' list ')' -/// copyprivate-clause: -/// 'copyprivate' '(' list ')' -/// flush-clause: -/// 'flush' '(' list ')' -/// depend-clause: -/// 'depend' '(' in | out | inout : list | source ')' -/// map-clause: -/// 'map' '(' [ [ always , ] -/// to | from | tofrom | alloc | release | delete ':' ] list ')'; -/// -/// For 'linear' clause linear-list may have the following forms: -/// list -/// modifier(list) -/// where modifier is 'val' (C) or 'ref', 'val' or 'uval'(C++). -OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, - OpenMPClauseKind Kind) { - SourceLocation Loc = Tok.getLocation(); - SourceLocation LOpen = ConsumeToken(); - SourceLocation ColonLoc = SourceLocation(); - // Optional scope specifier and unqualified id for reduction identifier. - CXXScopeSpec ReductionIdScopeSpec; - UnqualifiedId ReductionId; +/// Parses clauses with list. +bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, + OpenMPClauseKind Kind, + SmallVectorImpl<Expr *> &Vars, + OpenMPVarListDataTy &Data) { + UnqualifiedId UnqualifiedReductionId; bool InvalidReductionId = false; - OpenMPDependClauseKind DepKind = OMPC_DEPEND_unknown; - // OpenMP 4.1 [2.15.3.7, linear Clause] - // If no modifier is specified it is assumed to be val. - OpenMPLinearClauseKind LinearModifier = OMPC_LINEAR_val; - OpenMPMapClauseKind MapType = OMPC_MAP_unknown; - OpenMPMapClauseKind MapTypeModifier = OMPC_MAP_unknown; bool MapTypeModifierSpecified = false; - bool UnexpectedId = false; - SourceLocation DepLinMapLoc; // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, getOpenMPClauseName(Kind))) - return nullptr; + return true; bool NeedRParenForLinear = false; BalancedDelimiterTracker LinearT(*this, tok::l_paren, @@ -886,46 +1540,46 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, // Handle reduction-identifier for reduction clause. if (Kind == OMPC_reduction) { ColonProtectionRAIIObject ColonRAII(*this); - if (getLangOpts().CPlusPlus) { - ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec, ParsedType(), false); - } - InvalidReductionId = - ParseReductionId(*this, ReductionIdScopeSpec, ReductionId); + if (getLangOpts().CPlusPlus) + ParseOptionalCXXScopeSpecifier(Data.ReductionIdScopeSpec, + /*ObjectType=*/nullptr, + /*EnteringContext=*/false); + InvalidReductionId = ParseReductionId(*this, Data.ReductionIdScopeSpec, + UnqualifiedReductionId); if (InvalidReductionId) { SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } - if (Tok.is(tok::colon)) { - ColonLoc = ConsumeToken(); - } else { + if (Tok.is(tok::colon)) + Data.ColonLoc = ConsumeToken(); + else Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier"; - } + if (!InvalidReductionId) + Data.ReductionId = + Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId); } else if (Kind == OMPC_depend) { // Handle dependency type for depend clause. ColonProtectionRAIIObject ColonRAII(*this); - DepKind = static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType( - Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); - DepLinMapLoc = Tok.getLocation(); + Data.DepKind = + static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType( + Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); + Data.DepLinMapLoc = Tok.getLocation(); - if (DepKind == OMPC_DEPEND_unknown) { + if (Data.DepKind == OMPC_DEPEND_unknown) { SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } else { ConsumeToken(); // Special processing for depend(source) clause. - if (DKind == OMPD_ordered && DepKind == OMPC_DEPEND_source) { + if (DKind == OMPD_ordered && Data.DepKind == OMPC_DEPEND_source) { // Parse ')'. T.consumeClose(); - return Actions.ActOnOpenMPVarListClause( - Kind, llvm::None, /*TailExpr=*/nullptr, Loc, LOpen, - /*ColonLoc=*/SourceLocation(), Tok.getLocation(), - ReductionIdScopeSpec, DeclarationNameInfo(), DepKind, - LinearModifier, MapTypeModifier, MapType, DepLinMapLoc); + return false; } } - if (Tok.is(tok::colon)) { - ColonLoc = ConsumeToken(); - } else { + if (Tok.is(tok::colon)) + Data.ColonLoc = ConsumeToken(); + else { Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren : diag::warn_pragma_expected_colon) << "dependency type"; @@ -933,9 +1587,9 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, } else if (Kind == OMPC_linear) { // Try to parse modifier if any. if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) { - LinearModifier = static_cast<OpenMPLinearClauseKind>( + Data.LinKind = static_cast<OpenMPLinearClauseKind>( getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok))); - DepLinMapLoc = ConsumeToken(); + Data.DepLinMapLoc = ConsumeToken(); LinearT.consumeOpen(); NeedRParenForLinear = true; } @@ -943,71 +1597,78 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, // Handle map type for map clause. ColonProtectionRAIIObject ColonRAII(*this); - // the first identifier may be a list item, a map-type or - // a map-type-modifier - MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType( - Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); - DepLinMapLoc = Tok.getLocation(); + /// The map clause modifier token can be either a identifier or the C++ + /// delete keyword. + auto &&IsMapClauseModifierToken = [](const Token &Tok) -> bool { + return Tok.isOneOf(tok::identifier, tok::kw_delete); + }; + + // The first identifier may be a list item, a map-type or a + // map-type-modifier. The map modifier can also be delete which has the same + // spelling of the C++ delete keyword. + Data.MapType = + IsMapClauseModifierToken(Tok) + ? static_cast<OpenMPMapClauseKind>( + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok))) + : OMPC_MAP_unknown; + Data.DepLinMapLoc = Tok.getLocation(); bool ColonExpected = false; - if (Tok.is(tok::identifier)) { + if (IsMapClauseModifierToken(Tok)) { if (PP.LookAhead(0).is(tok::colon)) { - MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType( - Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); - if (MapType == OMPC_MAP_unknown) { + if (Data.MapType == OMPC_MAP_unknown) Diag(Tok, diag::err_omp_unknown_map_type); - } else if (MapType == OMPC_MAP_always) { + else if (Data.MapType == OMPC_MAP_always) Diag(Tok, diag::err_omp_map_type_missing); - } ConsumeToken(); } else if (PP.LookAhead(0).is(tok::comma)) { - if (PP.LookAhead(1).is(tok::identifier) && + if (IsMapClauseModifierToken(PP.LookAhead(1)) && PP.LookAhead(2).is(tok::colon)) { - MapTypeModifier = - static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType( - Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); - if (MapTypeModifier != OMPC_MAP_always) { + Data.MapTypeModifier = Data.MapType; + if (Data.MapTypeModifier != OMPC_MAP_always) { Diag(Tok, diag::err_omp_unknown_map_type_modifier); - MapTypeModifier = OMPC_MAP_unknown; - } else { + Data.MapTypeModifier = OMPC_MAP_unknown; + } else MapTypeModifierSpecified = true; - } ConsumeToken(); ConsumeToken(); - MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType( - Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); - if (MapType == OMPC_MAP_unknown || MapType == OMPC_MAP_always) { + Data.MapType = + IsMapClauseModifierToken(Tok) + ? static_cast<OpenMPMapClauseKind>( + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok))) + : OMPC_MAP_unknown; + if (Data.MapType == OMPC_MAP_unknown || + Data.MapType == OMPC_MAP_always) Diag(Tok, diag::err_omp_unknown_map_type); - } ConsumeToken(); } else { - MapType = OMPC_MAP_tofrom; + Data.MapType = OMPC_MAP_tofrom; + Data.IsMapTypeImplicit = true; } } else { - MapType = OMPC_MAP_tofrom; + Data.MapType = OMPC_MAP_tofrom; + Data.IsMapTypeImplicit = true; } } else { - UnexpectedId = true; + Data.MapType = OMPC_MAP_tofrom; + Data.IsMapTypeImplicit = true; } - if (Tok.is(tok::colon)) { - ColonLoc = ConsumeToken(); - } else if (ColonExpected) { + if (Tok.is(tok::colon)) + Data.ColonLoc = ConsumeToken(); + else if (ColonExpected) Diag(Tok, diag::warn_pragma_expected_colon) << "map type"; - } } - SmallVector<Expr *, 5> Vars; bool IsComma = - ((Kind != OMPC_reduction) && (Kind != OMPC_depend) && - (Kind != OMPC_map)) || - ((Kind == OMPC_reduction) && !InvalidReductionId) || - ((Kind == OMPC_map) && (UnexpectedId || MapType != OMPC_MAP_unknown) && + (Kind != OMPC_reduction && Kind != OMPC_depend && Kind != OMPC_map) || + (Kind == OMPC_reduction && !InvalidReductionId) || + (Kind == OMPC_map && Data.MapType != OMPC_MAP_unknown && (!MapTypeModifierSpecified || - (MapTypeModifierSpecified && MapTypeModifier == OMPC_MAP_always))) || - ((Kind == OMPC_depend) && DepKind != OMPC_DEPEND_unknown); + Data.MapTypeModifier == OMPC_MAP_always)) || + (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown); const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned); while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) && Tok.isNot(tok::annot_pragma_openmp_end))) { @@ -1015,9 +1676,9 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, // Parse variable ExprResult VarExpr = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); - if (VarExpr.isUsable()) { + if (VarExpr.isUsable()) Vars.push_back(VarExpr.get()); - } else { + else { SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } @@ -1039,15 +1700,14 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, LinearT.consumeClose(); // Parse ':' linear-step (or ':' alignment). - Expr *TailExpr = nullptr; const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon); if (MustHaveTail) { - ColonLoc = Tok.getLocation(); + Data.ColonLoc = Tok.getLocation(); SourceLocation ELoc = ConsumeToken(); ExprResult Tail = ParseAssignmentExpression(); Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc); if (Tail.isUsable()) - TailExpr = Tail.get(); + Data.TailExpr = Tail.get(); else SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -1055,18 +1715,67 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, // Parse ')'. T.consumeClose(); - if ((Kind == OMPC_depend && DepKind != OMPC_DEPEND_unknown && Vars.empty()) || - (Kind != OMPC_depend && Vars.empty()) || (MustHaveTail && !TailExpr) || - (Kind == OMPC_map && MapType == OMPC_MAP_unknown) || - InvalidReductionId) { + if ((Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown && + Vars.empty()) || + (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) || + (MustHaveTail && !Data.TailExpr) || InvalidReductionId) + return true; + return false; +} + +/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate', +/// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'. +/// +/// private-clause: +/// 'private' '(' list ')' +/// firstprivate-clause: +/// 'firstprivate' '(' list ')' +/// lastprivate-clause: +/// 'lastprivate' '(' list ')' +/// shared-clause: +/// 'shared' '(' list ')' +/// linear-clause: +/// 'linear' '(' linear-list [ ':' linear-step ] ')' +/// aligned-clause: +/// 'aligned' '(' list [ ':' alignment ] ')' +/// reduction-clause: +/// 'reduction' '(' reduction-identifier ':' list ')' +/// copyprivate-clause: +/// 'copyprivate' '(' list ')' +/// flush-clause: +/// 'flush' '(' list ')' +/// depend-clause: +/// 'depend' '(' in | out | inout : list | source ')' +/// map-clause: +/// 'map' '(' [ [ always , ] +/// to | from | tofrom | alloc | release | delete ':' ] list ')'; +/// to-clause: +/// 'to' '(' list ')' +/// from-clause: +/// 'from' '(' list ')' +/// use_device_ptr-clause: +/// 'use_device_ptr' '(' list ')' +/// is_device_ptr-clause: +/// 'is_device_ptr' '(' list ')' +/// +/// For 'linear' clause linear-list may have the following forms: +/// list +/// modifier(list) +/// where modifier is 'val' (C) or 'ref', 'val' or 'uval'(C++). +OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, + OpenMPClauseKind Kind) { + SourceLocation Loc = Tok.getLocation(); + SourceLocation LOpen = ConsumeToken(); + SmallVector<Expr *, 4> Vars; + OpenMPVarListDataTy Data; + + if (ParseOpenMPVarList(DKind, Kind, Vars, Data)) return nullptr; - } return Actions.ActOnOpenMPVarListClause( - Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(), - ReductionIdScopeSpec, - ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId) - : DeclarationNameInfo(), - DepKind, LinearModifier, MapTypeModifier, MapType, DepLinMapLoc); + Kind, Vars, Data.TailExpr, Loc, LOpen, Data.ColonLoc, Tok.getLocation(), + Data.ReductionIdScopeSpec, Data.ReductionId, Data.DepKind, Data.LinKind, + Data.MapTypeModifier, Data.MapType, Data.IsMapTypeImplicit, + Data.DepLinMapLoc); } diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index bc70942851e2..bff5d1170fe0 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -13,6 +13,7 @@ #include "RAIIObjectsForParser.h" #include "clang/AST/ASTContext.h" +#include "clang/Basic/PragmaKinds.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Parse/ParseDiagnostic.h" @@ -336,11 +337,9 @@ void Parser::HandlePragmaVisibility() { namespace { struct PragmaPackInfo { - Sema::PragmaPackKind Kind; - IdentifierInfo *Name; + Sema::PragmaMsStackAction Action; + StringRef SlotLabel; Token Alignment; - SourceLocation LParenLoc; - SourceLocation RParenLoc; }; } // end anonymous namespace @@ -355,15 +354,14 @@ void Parser::HandlePragmaPack() { if (Alignment.isInvalid()) return; } - Actions.ActOnPragmaPack(Info->Kind, Info->Name, Alignment.get(), PragmaLoc, - Info->LParenLoc, Info->RParenLoc); + Actions.ActOnPragmaPack(PragmaLoc, Info->Action, Info->SlotLabel, + Alignment.get()); } void Parser::HandlePragmaMSStruct() { assert(Tok.is(tok::annot_pragma_msstruct)); - Sema::PragmaMSStructKind Kind = - static_cast<Sema::PragmaMSStructKind>( - reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); + PragmaMSStructKind Kind = static_cast<PragmaMSStructKind>( + reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); Actions.ActOnPragmaMSStruct(Kind); ConsumeToken(); // The annotation token. } @@ -470,14 +468,24 @@ void Parser::HandlePragmaOpenCLExtension() { ConsumeToken(); // The annotation token. OpenCLOptions &f = Actions.getOpenCLOptions(); + auto CLVer = getLangOpts().OpenCLVersion; + auto &Supp = getTargetInfo().getSupportedOpenCLOpts(); // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions, // overriding all previously issued extension directives, but only if the // behavior is set to disable." if (state == 0 && ename->isStr("all")) { -#define OPENCLEXT(nm) f.nm = 0; +#define OPENCLEXT(nm) \ + if (Supp.is_##nm##_supported_extension(CLVer)) \ + f.nm = 0; #include "clang/Basic/OpenCLExtensions.def" } -#define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; } +#define OPENCLEXT(nm) else if (ename->isStr(#nm)) \ + if (Supp.is_##nm##_supported_extension(CLVer)) \ + f.nm = state; \ + else if (Supp.is_##nm##_supported_core(CLVer)) \ + PP.Diag(NameLoc, diag::warn_pragma_extension_is_core) << ename; \ + else \ + PP.Diag(NameLoc, diag::warn_pragma_unsupported_extension) << ename; #include "clang/Basic/OpenCLExtensions.def" else { PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename; @@ -497,18 +505,19 @@ void Parser::HandlePragmaMSPointersToMembers() { void Parser::HandlePragmaMSVtorDisp() { assert(Tok.is(tok::annot_pragma_ms_vtordisp)); uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()); - Sema::PragmaVtorDispKind Kind = - static_cast<Sema::PragmaVtorDispKind>((Value >> 16) & 0xFFFF); + Sema::PragmaMsStackAction Action = + static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF); MSVtorDispAttr::Mode Mode = MSVtorDispAttr::Mode(Value & 0xFFFF); SourceLocation PragmaLoc = ConsumeToken(); // The annotation token. - Actions.ActOnPragmaMSVtorDisp(Kind, PragmaLoc, Mode); + Actions.ActOnPragmaMSVtorDisp(Action, PragmaLoc, Mode); } void Parser::HandlePragmaMSPragma() { assert(Tok.is(tok::annot_pragma_ms_pragma)); // Grab the tokens out of the annotation and enter them into the stream. - auto TheTokens = (std::pair<Token*, size_t> *)Tok.getAnnotationValue(); - PP.EnterTokenStream(TheTokens->first, TheTokens->second, true, true); + auto TheTokens = + (std::pair<std::unique_ptr<Token[]>, size_t> *)Tok.getAnnotationValue(); + PP.EnterTokenStream(std::move(TheTokens->first), TheTokens->second, true); SourceLocation PragmaLocation = ConsumeToken(); // The annotation token. assert(Tok.isAnyIdentifier()); StringRef PragmaName = Tok.getIdentifierInfo()->getName(); @@ -798,14 +807,13 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) { Hint.OptionLoc = IdentifierLoc::create( Actions.Context, Info->Option.getLocation(), OptionInfo); - const Token *Toks = Info->Toks.data(); - size_t TokSize = Info->Toks.size(); + llvm::ArrayRef<Token> Toks = Info->Toks; // Return a valid hint if pragma unroll or nounroll were specified // without an argument. bool PragmaUnroll = PragmaNameInfo->getName() == "unroll"; bool PragmaNoUnroll = PragmaNameInfo->getName() == "nounroll"; - if (TokSize == 0 && (PragmaUnroll || PragmaNoUnroll)) { + if (Toks.empty() && (PragmaUnroll || PragmaNoUnroll)) { ConsumeToken(); // The annotation token. Hint.Range = Info->PragmaName.getLocation(); return true; @@ -813,26 +821,30 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) { // The constant expression is always followed by an eof token, which increases // the TokSize by 1. - assert(TokSize > 0 && + assert(!Toks.empty() && "PragmaLoopHintInfo::Toks must contain at least one token."); // If no option is specified the argument is assumed to be a constant expr. bool OptionUnroll = false; + bool OptionDistribute = false; bool StateOption = false; if (OptionInfo) { // Pragma Unroll does not specify an option. OptionUnroll = OptionInfo->isStr("unroll"); + OptionDistribute = OptionInfo->isStr("distribute"); StateOption = llvm::StringSwitch<bool>(OptionInfo->getName()) .Case("vectorize", true) .Case("interleave", true) - .Case("unroll", true) - .Default(false); + .Default(false) || + OptionUnroll || OptionDistribute; } + bool AssumeSafetyArg = !OptionUnroll && !OptionDistribute; // Verify loop hint has an argument. if (Toks[0].is(tok::eof)) { ConsumeToken(); // The annotation token. Diag(Toks[0].getLocation(), diag::err_pragma_loop_missing_argument) - << /*StateArgument=*/StateOption << /*FullKeyword=*/OptionUnroll; + << /*StateArgument=*/StateOption << /*FullKeyword=*/OptionUnroll + << /*AssumeSafetyKeyword=*/AssumeSafetyArg; return false; } @@ -841,22 +853,26 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) { ConsumeToken(); // The annotation token. SourceLocation StateLoc = Toks[0].getLocation(); IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo(); - if (!StateInfo || - (!StateInfo->isStr("enable") && !StateInfo->isStr("disable") && - ((OptionUnroll && !StateInfo->isStr("full")) || - (!OptionUnroll && !StateInfo->isStr("assume_safety"))))) { + + bool Valid = StateInfo && + llvm::StringSwitch<bool>(StateInfo->getName()) + .Cases("enable", "disable", true) + .Case("full", OptionUnroll) + .Case("assume_safety", AssumeSafetyArg) + .Default(false); + if (!Valid) { Diag(Toks[0].getLocation(), diag::err_pragma_invalid_keyword) - << /*FullKeyword=*/OptionUnroll; + << /*FullKeyword=*/OptionUnroll + << /*AssumeSafetyKeyword=*/AssumeSafetyArg; return false; } - if (TokSize > 2) + if (Toks.size() > 2) Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << PragmaLoopHintString(Info->PragmaName, Info->Option); Hint.StateLoc = IdentifierLoc::create(Actions.Context, StateLoc, StateInfo); } else { // Enter constant expression including eof terminator into token stream. - PP.EnterTokenStream(Toks, TokSize, /*DisableMacroExpansion=*/false, - /*OwnsTokens=*/false); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/false); ConsumeToken(); // The annotation token. ExprResult R = ParseConstantExpression(); @@ -881,7 +897,7 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) { } Hint.Range = SourceRange(Info->PragmaName.getLocation(), - Info->Toks[TokSize - 1].getLocation()); + Info->Toks.back().getLocation()); return true; } @@ -934,15 +950,14 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, return; } - Token *Toks = new Token[1]; + auto Toks = llvm::make_unique<Token[]>(1); Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_vis); Toks[0].setLocation(VisLoc); Toks[0].setAnnotationEndLoc(EndLoc); Toks[0].setAnnotationValue( const_cast<void*>(static_cast<const void*>(VisType))); - PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, - /*OwnsTokens=*/true); + PP.EnterTokenStream(std::move(Toks), 1, /*DisableMacroExpansion=*/true); } // #pragma pack(...) comes in the following delicious flavors: @@ -961,11 +976,10 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, return; } - Sema::PragmaPackKind Kind = Sema::PPK_Default; - IdentifierInfo *Name = nullptr; + Sema::PragmaMsStackAction Action = Sema::PSK_Reset; + StringRef SlotLabel; Token Alignment; Alignment.startToken(); - SourceLocation LParenLoc = Tok.getLocation(); PP.Lex(Tok); if (Tok.is(tok::numeric_constant)) { Alignment = Tok; @@ -975,18 +989,18 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, // In MSVC/gcc, #pragma pack(4) sets the alignment without affecting // the push/pop stack. // In Apple gcc, #pragma pack(4) is equivalent to #pragma pack(push, 4) - if (PP.getLangOpts().ApplePragmaPack) - Kind = Sema::PPK_Push; + Action = + PP.getLangOpts().ApplePragmaPack ? Sema::PSK_Push_Set : Sema::PSK_Set; } else if (Tok.is(tok::identifier)) { const IdentifierInfo *II = Tok.getIdentifierInfo(); if (II->isStr("show")) { - Kind = Sema::PPK_Show; + Action = Sema::PSK_Show; PP.Lex(Tok); } else { if (II->isStr("push")) { - Kind = Sema::PPK_Push; + Action = Sema::PSK_Push; } else if (II->isStr("pop")) { - Kind = Sema::PPK_Pop; + Action = Sema::PSK_Pop; } else { PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_action) << "pack"; return; @@ -997,11 +1011,12 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, PP.Lex(Tok); if (Tok.is(tok::numeric_constant)) { + Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set); Alignment = Tok; PP.Lex(Tok); } else if (Tok.is(tok::identifier)) { - Name = Tok.getIdentifierInfo(); + SlotLabel = Tok.getIdentifierInfo()->getName(); PP.Lex(Tok); if (Tok.is(tok::comma)) { @@ -1012,6 +1027,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, return; } + Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set); Alignment = Tok; PP.Lex(Tok); @@ -1026,7 +1042,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, // In MSVC/gcc, #pragma pack() resets the alignment without affecting // the push/pop stack. // In Apple gcc #pragma pack() is equivalent to #pragma pack(pop). - Kind = Sema::PPK_Pop; + Action = Sema::PSK_Pop; } if (Tok.isNot(tok::r_paren)) { @@ -1041,27 +1057,20 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, return; } - PragmaPackInfo *Info = - (PragmaPackInfo*) PP.getPreprocessorAllocator().Allocate( - sizeof(PragmaPackInfo), llvm::alignOf<PragmaPackInfo>()); - new (Info) PragmaPackInfo(); - Info->Kind = Kind; - Info->Name = Name; + PragmaPackInfo *Info = + PP.getPreprocessorAllocator().Allocate<PragmaPackInfo>(1); + Info->Action = Action; + Info->SlotLabel = SlotLabel; Info->Alignment = Alignment; - Info->LParenLoc = LParenLoc; - Info->RParenLoc = RParenLoc; - Token *Toks = - (Token*) PP.getPreprocessorAllocator().Allocate( - sizeof(Token) * 1, llvm::alignOf<Token>()); - new (Toks) Token(); + MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), + 1); Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_pack); Toks[0].setLocation(PackLoc); Toks[0].setAnnotationEndLoc(RParenLoc); Toks[0].setAnnotationValue(static_cast<void*>(Info)); - PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, - /*OwnsTokens=*/false); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); } // #pragma ms_struct on @@ -1069,8 +1078,8 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &MSStructTok) { - Sema::PragmaMSStructKind Kind = Sema::PMSST_OFF; - + PragmaMSStructKind Kind = PMSST_OFF; + Token Tok; PP.Lex(Tok); if (Tok.isNot(tok::identifier)) { @@ -1080,7 +1089,7 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, SourceLocation EndLoc = Tok.getLocation(); const IdentifierInfo *II = Tok.getIdentifierInfo(); if (II->isStr("on")) { - Kind = Sema::PMSST_ON; + Kind = PMSST_ON; PP.Lex(Tok); } else if (II->isStr("off") || II->isStr("reset")) @@ -1096,18 +1105,15 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, return; } - Token *Toks = - (Token*) PP.getPreprocessorAllocator().Allocate( - sizeof(Token) * 1, llvm::alignOf<Token>()); - new (Toks) Token(); + MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), + 1); Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_msstruct); Toks[0].setLocation(MSStructTok.getLocation()); Toks[0].setAnnotationEndLoc(EndLoc); Toks[0].setAnnotationValue(reinterpret_cast<void*>( static_cast<uintptr_t>(Kind))); - PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, - /*OwnsTokens=*/false); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); } // #pragma 'align' '=' {'native','natural','mac68k','power','reset'} @@ -1167,18 +1173,15 @@ static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok, return; } - Token *Toks = - (Token*) PP.getPreprocessorAllocator().Allocate( - sizeof(Token) * 1, llvm::alignOf<Token>()); - new (Toks) Token(); + MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), + 1); Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_align); Toks[0].setLocation(FirstTok.getLocation()); Toks[0].setAnnotationEndLoc(EndLoc); Toks[0].setAnnotationValue(reinterpret_cast<void*>( static_cast<uintptr_t>(Kind))); - PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, - /*OwnsTokens=*/false); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); } void PragmaAlignHandler::HandlePragma(Preprocessor &PP, @@ -1260,9 +1263,9 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, // This allows us to cache a "#pragma unused" that occurs inside an inline // C++ member function. - Token *Toks = - (Token*) PP.getPreprocessorAllocator().Allocate( - sizeof(Token) * 2 * Identifiers.size(), llvm::alignOf<Token>()); + MutableArrayRef<Token> Toks( + PP.getPreprocessorAllocator().Allocate<Token>(2 * Identifiers.size()), + 2 * Identifiers.size()); for (unsigned i=0; i != Identifiers.size(); i++) { Token &pragmaUnusedTok = Toks[2*i], &idTok = Toks[2*i+1]; pragmaUnusedTok.startToken(); @@ -1270,8 +1273,7 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, pragmaUnusedTok.setLocation(UnusedLoc); idTok = Identifiers[i]; } - PP.EnterTokenStream(Toks, 2*Identifiers.size(), - /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); } // #pragma weak identifier @@ -1311,9 +1313,8 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, } if (HasAlias) { - Token *Toks = - (Token*) PP.getPreprocessorAllocator().Allocate( - sizeof(Token) * 3, llvm::alignOf<Token>()); + MutableArrayRef<Token> Toks( + PP.getPreprocessorAllocator().Allocate<Token>(3), 3); Token &pragmaUnusedTok = Toks[0]; pragmaUnusedTok.startToken(); pragmaUnusedTok.setKind(tok::annot_pragma_weakalias); @@ -1321,20 +1322,17 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, pragmaUnusedTok.setAnnotationEndLoc(AliasName.getLocation()); Toks[1] = WeakName; Toks[2] = AliasName; - PP.EnterTokenStream(Toks, 3, - /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); } else { - Token *Toks = - (Token*) PP.getPreprocessorAllocator().Allocate( - sizeof(Token) * 2, llvm::alignOf<Token>()); + MutableArrayRef<Token> Toks( + PP.getPreprocessorAllocator().Allocate<Token>(2), 2); Token &pragmaUnusedTok = Toks[0]; pragmaUnusedTok.startToken(); pragmaUnusedTok.setKind(tok::annot_pragma_weak); pragmaUnusedTok.setLocation(WeakLoc); pragmaUnusedTok.setAnnotationEndLoc(WeakLoc); Toks[1] = WeakName; - PP.EnterTokenStream(Toks, 2, - /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); } } @@ -1370,9 +1368,8 @@ void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP, return; } - Token *Toks = - (Token*) PP.getPreprocessorAllocator().Allocate( - sizeof(Token) * 3, llvm::alignOf<Token>()); + MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(3), + 3); Token &pragmaRedefTok = Toks[0]; pragmaRedefTok.startToken(); pragmaRedefTok.setKind(tok::annot_pragma_redefine_extname); @@ -1380,8 +1377,7 @@ void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP, pragmaRedefTok.setAnnotationEndLoc(AliasName.getLocation()); Toks[1] = RedefName; Toks[2] = AliasName; - PP.EnterTokenStream(Toks, 3, - /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); } @@ -1393,18 +1389,15 @@ PragmaFPContractHandler::HandlePragma(Preprocessor &PP, if (PP.LexOnOffSwitch(OOS)) return; - Token *Toks = - (Token*) PP.getPreprocessorAllocator().Allocate( - sizeof(Token) * 1, llvm::alignOf<Token>()); - new (Toks) Token(); + MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), + 1); Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_fp_contract); Toks[0].setLocation(Tok.getLocation()); Toks[0].setAnnotationEndLoc(Tok.getLocation()); Toks[0].setAnnotationValue(reinterpret_cast<void*>( static_cast<uintptr_t>(OOS))); - PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, - /*OwnsTokens=*/false); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); } void @@ -1452,17 +1445,14 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, } OpenCLExtData data(ename, state); - Token *Toks = - (Token*) PP.getPreprocessorAllocator().Allocate( - sizeof(Token) * 1, llvm::alignOf<Token>()); - new (Toks) Token(); + MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), + 1); Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_opencl_extension); Toks[0].setLocation(NameLoc); Toks[0].setAnnotationValue(data.getOpaqueValue()); Toks[0].setAnnotationEndLoc(StateLoc); - PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, - /*OwnsTokens=*/false); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); if (PP.getPPCallbacks()) PP.getPPCallbacks()->PragmaOpenCLExtension(NameLoc, ename, @@ -1506,10 +1496,10 @@ PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, Tok.setLocation(EodLoc); Pragma.push_back(Tok); - Token *Toks = new Token[Pragma.size()]; - std::copy(Pragma.begin(), Pragma.end(), Toks); - PP.EnterTokenStream(Toks, Pragma.size(), - /*DisableMacroExpansion=*/false, /*OwnsTokens=*/true); + auto Toks = llvm::make_unique<Token[]>(Pragma.size()); + std::copy(Pragma.begin(), Pragma.end(), Toks.get()); + PP.EnterTokenStream(std::move(Toks), Pragma.size(), + /*DisableMacroExpansion=*/false); } /// \brief Handle '#pragma pointers_to_members' @@ -1629,7 +1619,7 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP, } PP.Lex(Tok); - Sema::PragmaVtorDispKind Kind = Sema::PVDK_Set; + Sema::PragmaMsStackAction Action = Sema::PSK_Set; const IdentifierInfo *II = Tok.getIdentifierInfo(); if (II) { if (II->isStr("push")) { @@ -1640,24 +1630,24 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP, return; } PP.Lex(Tok); - Kind = Sema::PVDK_Push; + Action = Sema::PSK_Push_Set; // not push, could be on/off } else if (II->isStr("pop")) { // #pragma vtordisp(pop) PP.Lex(Tok); - Kind = Sema::PVDK_Pop; + Action = Sema::PSK_Pop; } // not push or pop, could be on/off } else { if (Tok.is(tok::r_paren)) { // #pragma vtordisp() - Kind = Sema::PVDK_Reset; + Action = Sema::PSK_Reset; } } uint64_t Value = 0; - if (Kind == Sema::PVDK_Push || Kind == Sema::PVDK_Set) { + if (Action & Sema::PSK_Push || Action & Sema::PSK_Set) { const IdentifierInfo *II = Tok.getIdentifierInfo(); if (II && II->isStr("off")) { PP.Lex(Tok); @@ -1699,7 +1689,7 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP, AnnotTok.setLocation(VtorDispLoc); AnnotTok.setAnnotationEndLoc(EndLoc); AnnotTok.setAnnotationValue(reinterpret_cast<void *>( - static_cast<uintptr_t>((Kind << 16) | (Value & 0xFFFF)))); + static_cast<uintptr_t>((Action << 16) | (Value & 0xFFFF)))); PP.EnterToken(AnnotTok); } @@ -1725,10 +1715,11 @@ void PragmaMSPragma::HandlePragma(Preprocessor &PP, TokenVector.push_back(EoF); // We must allocate this array with new because EnterTokenStream is going to // delete it later. - Token *TokenArray = new Token[TokenVector.size()]; - std::copy(TokenVector.begin(), TokenVector.end(), TokenArray); + auto TokenArray = llvm::make_unique<Token[]>(TokenVector.size()); + std::copy(TokenVector.begin(), TokenVector.end(), TokenArray.get()); auto Value = new (PP.getPreprocessorAllocator()) - std::pair<Token*, size_t>(std::make_pair(TokenArray, TokenVector.size())); + std::pair<std::unique_ptr<Token[]>, size_t>(std::move(TokenArray), + TokenVector.size()); AnnotTok.setAnnotationValue(Value); PP.EnterToken(AnnotTok); } @@ -1746,10 +1737,10 @@ void PragmaMSPragma::HandlePragma(Preprocessor &PP, void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &Tok) { - SourceLocation CommentLoc = Tok.getLocation(); + SourceLocation DetectMismatchLoc = Tok.getLocation(); PP.Lex(Tok); if (Tok.isNot(tok::l_paren)) { - PP.Diag(CommentLoc, diag::err_expected) << tok::l_paren; + PP.Diag(DetectMismatchLoc, diag::err_expected) << tok::l_paren; return; } @@ -1784,10 +1775,10 @@ void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP, // If the pragma is lexically sound, notify any interested PPCallbacks. if (PP.getPPCallbacks()) - PP.getPPCallbacks()->PragmaDetectMismatch(CommentLoc, NameString, + PP.getPPCallbacks()->PragmaDetectMismatch(DetectMismatchLoc, NameString, ValueString); - Actions.ActOnPragmaDetectMismatch(NameString, ValueString); + Actions.ActOnPragmaDetectMismatch(DetectMismatchLoc, NameString, ValueString); } /// \brief Handle the microsoft \#pragma comment extension. @@ -1818,22 +1809,22 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, // Verify that this is one of the 5 whitelisted options. IdentifierInfo *II = Tok.getIdentifierInfo(); - Sema::PragmaMSCommentKind Kind = - llvm::StringSwitch<Sema::PragmaMSCommentKind>(II->getName()) - .Case("linker", Sema::PCK_Linker) - .Case("lib", Sema::PCK_Lib) - .Case("compiler", Sema::PCK_Compiler) - .Case("exestr", Sema::PCK_ExeStr) - .Case("user", Sema::PCK_User) - .Default(Sema::PCK_Unknown); - if (Kind == Sema::PCK_Unknown) { + PragmaMSCommentKind Kind = + llvm::StringSwitch<PragmaMSCommentKind>(II->getName()) + .Case("linker", PCK_Linker) + .Case("lib", PCK_Lib) + .Case("compiler", PCK_Compiler) + .Case("exestr", PCK_ExeStr) + .Case("user", PCK_User) + .Default(PCK_Unknown); + if (Kind == PCK_Unknown) { PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind); return; } // On PS4, issue a warning about any pragma comments other than // #pragma comment lib. - if (PP.getTargetInfo().getTriple().isPS4() && Kind != Sema::PCK_Lib) { + if (PP.getTargetInfo().getTriple().isPS4() && Kind != PCK_Lib) { PP.Diag(Tok.getLocation(), diag::warn_pragma_comment_ignored) << II->getName(); return; @@ -1869,7 +1860,7 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, if (PP.getPPCallbacks()) PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString); - Actions.ActOnPragmaMSComment(Kind, ArgumentString); + Actions.ActOnPragmaMSComment(CommentLoc, Kind, ArgumentString); } // #pragma clang optimize off @@ -2020,6 +2011,7 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, .Case("vectorize", true) .Case("interleave", true) .Case("unroll", true) + .Case("distribute", true) .Case("vectorize_width", true) .Case("interleave_count", true) .Case("unroll_count", true) @@ -2059,12 +2051,11 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, return; } - Token *TokenArray = new Token[TokenList.size()]; - std::copy(TokenList.begin(), TokenList.end(), TokenArray); + auto TokenArray = llvm::make_unique<Token[]>(TokenList.size()); + std::copy(TokenList.begin(), TokenList.end(), TokenArray.get()); - PP.EnterTokenStream(TokenArray, TokenList.size(), - /*DisableMacroExpansion=*/false, - /*OwnsTokens=*/true); + PP.EnterTokenStream(std::move(TokenArray), TokenList.size(), + /*DisableMacroExpansion=*/false); } /// \brief Handle the loop unroll optimization pragmas. @@ -2127,12 +2118,12 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP, } // Generate the hint token. - Token *TokenArray = new Token[1]; + auto TokenArray = llvm::make_unique<Token[]>(1); TokenArray[0].startToken(); TokenArray[0].setKind(tok::annot_pragma_loop_hint); TokenArray[0].setLocation(PragmaName.getLocation()); TokenArray[0].setAnnotationEndLoc(PragmaName.getLocation()); TokenArray[0].setAnnotationValue(static_cast<void *>(Info)); - PP.EnterTokenStream(TokenArray, 1, /*DisableMacroExpansion=*/false, - /*OwnsTokens=*/true); + PP.EnterTokenStream(std::move(TokenArray), 1, + /*DisableMacroExpansion=*/false); } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index edf0dda7df8c..fa8eb12044be 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -107,6 +107,8 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, ParsedAttributesWithRange Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true); + if (!MaybeParseOpenCLUnrollHintAttribute(Attrs)) + return StmtError(); StmtResult Res = ParseStatementOrDeclarationAfterAttributes( Stmts, Allowed, TrailingElseLoc, Attrs); @@ -1041,7 +1043,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { /// ParseParenExprOrCondition: /// [C ] '(' expression ')' -/// [C++] '(' condition ')' [not allowed if OnlyAllowCondition=true] +/// [C++] '(' condition ')' +/// [C++1z] '(' init-statement[opt] condition ')' /// /// This function parses and performs error recovery on the specified condition /// or expression (depending on whether we're in C++ or C mode). This function @@ -1050,29 +1053,29 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { /// should try to recover harder. It returns false if the condition is /// successfully parsed. Note that a successful parse can still have semantic /// errors in the condition. -bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, - Decl *&DeclResult, +bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, + Sema::ConditionResult &Cond, SourceLocation Loc, - bool ConvertToBoolean) { + Sema::ConditionKind CK) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); if (getLangOpts().CPlusPlus) - ParseCXXCondition(ExprResult, DeclResult, Loc, ConvertToBoolean); + Cond = ParseCXXCondition(InitStmt, Loc, CK); else { - ExprResult = ParseExpression(); - DeclResult = nullptr; + ExprResult CondExpr = ParseExpression(); // If required, convert to a boolean value. - if (!ExprResult.isInvalid() && ConvertToBoolean) - ExprResult - = Actions.ActOnBooleanCondition(getCurScope(), Loc, ExprResult.get()); + if (CondExpr.isInvalid()) + Cond = Sema::ConditionError(); + else + Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK); } // If the parser was confused by the condition and we don't have a ')', try to // recover by skipping ahead to a semi and bailing out. If condexp is // semantically invalid but we have well formed code, keep going. - if (ExprResult.isInvalid() && !DeclResult && Tok.isNot(tok::r_paren)) { + if (Cond.isInvalid() && Tok.isNot(tok::r_paren)) { SkipUntil(tok::semi); // Skipping may have stopped if it found the containing ')'. If so, we can // continue parsing the if statement. @@ -1107,6 +1110,14 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_if) && "Not an if stmt!"); SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. + bool IsConstexpr = false; + if (Tok.is(tok::kw_constexpr)) { + Diag(Tok, getLangOpts().CPlusPlus1z ? diag::warn_cxx14_compat_constexpr_if + : diag::ext_constexpr_if); + IsConstexpr = true; + ConsumeToken(); + } + if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "if"; SkipUntil(tok::semi); @@ -1130,12 +1141,16 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX); // Parse the condition. - ExprResult CondExp; - Decl *CondVar = nullptr; - if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true)) + StmtResult InitStmt; + Sema::ConditionResult Cond; + if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc, + IsConstexpr ? Sema::ConditionKind::ConstexprIf + : Sema::ConditionKind::Boolean)) return StmtError(); - FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp.get(), IfLoc)); + llvm::Optional<bool> ConstexprCondition; + if (IsConstexpr) + ConstexprCondition = Cond.getKnownValue(); // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this @@ -1161,7 +1176,13 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { SourceLocation ThenStmtLoc = Tok.getLocation(); SourceLocation InnerStatementTrailingElseLoc; - StmtResult ThenStmt(ParseStatement(&InnerStatementTrailingElseLoc)); + StmtResult ThenStmt; + { + EnterExpressionEvaluationContext PotentiallyDiscarded( + Actions, Sema::DiscardedStatement, nullptr, false, + /*ShouldEnter=*/ConstexprCondition && !*ConstexprCondition); + ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc); + } // Pop the 'if' scope if needed. InnerScope.Exit(); @@ -1187,8 +1208,12 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { // The substatement in a selection-statement (each substatement, in the else // form of the if statement) implicitly defines a local scope. // - ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); + ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, + Tok.is(tok::l_brace)); + EnterExpressionEvaluationContext PotentiallyDiscarded( + Actions, Sema::DiscardedStatement, nullptr, false, + /*ShouldEnter=*/ConstexprCondition && *ConstexprCondition); ElseStmt = ParseStatement(); // Pop the 'else' scope if needed. @@ -1219,8 +1244,8 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { if (ElseStmt.isInvalid()) ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); - return Actions.ActOnIfStmt(IfLoc, FullCondExp, CondVar, ThenStmt.get(), - ElseLoc, ElseStmt.get()); + return Actions.ActOnIfStmt(IfLoc, IsConstexpr, InitStmt.get(), Cond, + ThenStmt.get(), ElseLoc, ElseStmt.get()); } /// ParseSwitchStatement @@ -1257,13 +1282,14 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) { ParseScope SwitchScope(this, ScopeFlags); // Parse the condition. - ExprResult Cond; - Decl *CondVar = nullptr; - if (ParseParenExprOrCondition(Cond, CondVar, SwitchLoc, false)) + StmtResult InitStmt; + Sema::ConditionResult Cond; + if (ParseParenExprOrCondition(&InitStmt, Cond, SwitchLoc, + Sema::ConditionKind::Switch)) return StmtError(); - StmtResult Switch - = Actions.ActOnStartOfSwitchStmt(SwitchLoc, Cond.get(), CondVar); + StmtResult Switch = + Actions.ActOnStartOfSwitchStmt(SwitchLoc, InitStmt.get(), Cond); if (Switch.isInvalid()) { // Skip the switch body. @@ -1345,13 +1371,11 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) { ParseScope WhileScope(this, ScopeFlags); // Parse the condition. - ExprResult Cond; - Decl *CondVar = nullptr; - if (ParseParenExprOrCondition(Cond, CondVar, WhileLoc, true)) + Sema::ConditionResult Cond; + if (ParseParenExprOrCondition(nullptr, Cond, WhileLoc, + Sema::ConditionKind::Boolean)) return StmtError(); - FullExprArg FullCond(Actions.MakeFullExpr(Cond.get(), WhileLoc)); - // C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. @@ -1372,10 +1396,10 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) { InnerScope.Exit(); WhileScope.Exit(); - if ((Cond.isInvalid() && !CondVar) || Body.isInvalid()) + if (Cond.isInvalid() || Body.isInvalid()) return StmtError(); - return Actions.ActOnWhileStmt(WhileLoc, FullCond, CondVar, Body.get()); + return Actions.ActOnWhileStmt(WhileLoc, Cond, Body.get()); } /// ParseDoStatement @@ -1533,12 +1557,10 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { bool ForEach = false, ForRange = false; StmtResult FirstPart; - bool SecondPartIsInvalid = false; - FullExprArg SecondPart(Actions); + Sema::ConditionResult SecondPart; ExprResult Collection; ForRangeInit ForRangeInit; FullExprArg ThirdPart(Actions); - Decl *SecondVar = nullptr; if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), @@ -1632,7 +1654,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { ConsumeToken(); // consume 'in' if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCForCollection(getCurScope(), DeclGroupPtrTy()); + Actions.CodeCompleteObjCForCollection(getCurScope(), nullptr); cutOffParsing(); return StmtError(); } @@ -1643,7 +1665,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { Diag(Tok, diag::err_for_range_expected_decl) << FirstPart.get()->getSourceRange(); SkipUntil(tok::r_paren, StopBeforeMatch); - SecondPartIsInvalid = true; + SecondPart = Sema::ConditionError(); } else { if (!Value.isInvalid()) { Diag(Tok, diag::err_expected_semi_for); @@ -1658,29 +1680,29 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { // Parse the second part of the for specifier. getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope); - if (!ForEach && !ForRange) { - assert(!SecondPart.get() && "Shouldn't have a second expression yet."); + if (!ForEach && !ForRange && !SecondPart.isInvalid()) { // Parse the second part of the for specifier. if (Tok.is(tok::semi)) { // for (...;; // no second part. } else if (Tok.is(tok::r_paren)) { // missing both semicolons. } else { - ExprResult Second; if (getLangOpts().CPlusPlus) - ParseCXXCondition(Second, SecondVar, ForLoc, true); + SecondPart = + ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean); else { - Second = ParseExpression(); - if (!Second.isInvalid()) - Second = Actions.ActOnBooleanCondition(getCurScope(), ForLoc, - Second.get()); + ExprResult SecondExpr = ParseExpression(); + if (SecondExpr.isInvalid()) + SecondPart = Sema::ConditionError(); + else + SecondPart = + Actions.ActOnCondition(getCurScope(), ForLoc, SecondExpr.get(), + Sema::ConditionKind::Boolean); } - SecondPartIsInvalid = Second.isInvalid(); - SecondPart = Actions.MakeFullExpr(Second.get(), ForLoc); } if (Tok.isNot(tok::semi)) { - if (!SecondPartIsInvalid || SecondVar) + if (!SecondPart.isInvalid()) Diag(Tok, diag::err_expected_semi_for); else // Skip until semicolon or rparen, don't consume it. @@ -1716,9 +1738,11 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { StmtResult ForEachStmt; if (ForRange) { + ExprResult CorrectedRange = + Actions.CorrectDelayedTyposInExpr(ForRangeInit.RangeExpr.get()); ForRangeStmt = Actions.ActOnCXXForRangeStmt( getCurScope(), ForLoc, CoawaitLoc, FirstPart.get(), - ForRangeInit.ColonLoc, ForRangeInit.RangeExpr.get(), + ForRangeInit.ColonLoc, CorrectedRange.get(), T.getCloseLocation(), Sema::BFRK_Build); // Similarly, we need to do the semantic analysis for a for-range @@ -1777,8 +1801,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { return Actions.FinishCXXForRangeStmt(ForRangeStmt.get(), Body.get()); return Actions.ActOnForStmt(ForLoc, T.getOpenLocation(), FirstPart.get(), - SecondPart, SecondVar, ThirdPart, - T.getCloseLocation(), Body.get()); + SecondPart, ThirdPart, T.getCloseLocation(), + Body.get()); } /// ParseGotoStatement @@ -1912,19 +1936,14 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { assert(Tok.is(tok::l_brace)); SourceLocation LBraceLoc = Tok.getLocation(); - if (SkipFunctionBodies && (!Decl || Actions.canSkipFunctionBody(Decl)) && - trySkippingFunctionBody()) { - BodyScope.Exit(); - return Actions.ActOnSkippedFunctionBody(Decl); - } - PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc, "parsing function body"); // Save and reset current vtordisp stack if we have entered a C++ method body. bool IsCXXMethod = getLangOpts().CPlusPlus && Decl && isa<CXXMethodDecl>(Decl); - Sema::VtorDispStackRAII SavedVtorDispStack(Actions, IsCXXMethod); + Sema::PragmaStackSentinelRAII + PragmaStackSentinel(Actions, "InternalPragmaState", IsCXXMethod); // Do not enter a scope for the brace, as the arguments are in the same scope // (the function body) as the body itself. Instead, just read the statement @@ -1959,16 +1978,11 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { else Actions.ActOnDefaultCtorInitializers(Decl); - if (SkipFunctionBodies && Actions.canSkipFunctionBody(Decl) && - trySkippingFunctionBody()) { - BodyScope.Exit(); - return Actions.ActOnSkippedFunctionBody(Decl); - } - // Save and reset current vtordisp stack if we have entered a C++ method body. bool IsCXXMethod = getLangOpts().CPlusPlus && Decl && isa<CXXMethodDecl>(Decl); - Sema::VtorDispStackRAII SavedVtorDispStack(Actions, IsCXXMethod); + Sema::PragmaStackSentinelRAII + PragmaStackSentinel(Actions, "InternalPragmaState", IsCXXMethod); SourceLocation LBraceLoc = Tok.getLocation(); StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc, /*FnTry*/true)); @@ -1984,27 +1998,43 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { } bool Parser::trySkippingFunctionBody() { - assert(Tok.is(tok::l_brace)); assert(SkipFunctionBodies && "Should only be called when SkipFunctionBodies is enabled"); - if (!PP.isCodeCompletionEnabled()) { - ConsumeBrace(); - SkipUntil(tok::r_brace); + SkipFunctionBody(); return true; } // We're in code-completion mode. Skip parsing for all function bodies unless // the body contains the code-completion point. TentativeParsingAction PA(*this); - ConsumeBrace(); - if (SkipUntil(tok::r_brace, StopAtCodeCompletion)) { + bool IsTryCatch = Tok.is(tok::kw_try); + CachedTokens Toks; + bool ErrorInPrologue = ConsumeAndStoreFunctionPrologue(Toks); + if (llvm::any_of(Toks, [](const Token &Tok) { + return Tok.is(tok::code_completion); + })) { + PA.Revert(); + return false; + } + if (ErrorInPrologue) { PA.Commit(); + SkipMalformedDecl(); return true; } - - PA.Revert(); - return false; + if (!SkipUntil(tok::r_brace, StopAtCodeCompletion)) { + PA.Revert(); + return false; + } + while (IsTryCatch && Tok.is(tok::kw_catch)) { + if (!SkipUntil(tok::l_brace, StopAtCodeCompletion) || + !SkipUntil(tok::r_brace, StopAtCodeCompletion)) { + PA.Revert(); + return false; + } + } + PA.Commit(); + return true; } /// ParseCXXTryBlock - Parse a C++ try-block. @@ -2206,3 +2236,19 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { } Braces.consumeClose(); } + +bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) { + MaybeParseGNUAttributes(Attrs); + + if (Attrs.empty()) + return true; + + if (Attrs.getList()->getKind() != AttributeList::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/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp index 142b473755de..1f63dc257b86 100644 --- a/lib/Parse/ParseStmtAsm.cpp +++ b/lib/Parse/ParseStmtAsm.cpp @@ -17,16 +17,17 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/MC/MCTargetAsmParser.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" @@ -199,9 +200,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, // Also copy the current token over. LineToks.push_back(Tok); - PP.EnterTokenStream(LineToks.begin(), LineToks.size(), - /*disable macros*/ true, - /*owns tokens*/ false); + PP.EnterTokenStream(LineToks, /*DisableMacroExpansions*/ true); // Clear the current token and advance to the first token in LineToks. ConsumeAnyToken(); @@ -209,7 +208,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, // Parse an optional scope-specifier if we're in C++. CXXScopeSpec SS; if (getLangOpts().CPlusPlus) { - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); } // Require an identifier here. @@ -221,12 +220,11 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, Result = ParseCXXThis(); Invalid = false; } else { - Invalid = - ParseUnqualifiedId(SS, - /*EnteringContext=*/false, - /*AllowDestructorName=*/false, - /*AllowConstructorName=*/false, - /*ObjectType=*/ParsedType(), TemplateKWLoc, Id); + Invalid = ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/false, + /*AllowConstructorName=*/false, + /*ObjectType=*/nullptr, TemplateKWLoc, Id); // Perform the lookup. Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info, IsUnevaluatedContext); @@ -337,6 +335,33 @@ static bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc, return false; } +/// isTypeQualifier - Return true if the current token could be the +/// start of a type-qualifier-list. +static bool isTypeQualifier(const Token &Tok) { + switch (Tok.getKind()) { + default: return false; + // type-qualifier + case tok::kw_const: + case tok::kw_volatile: + case tok::kw_restrict: + case tok::kw___private: + case tok::kw___local: + case tok::kw___global: + case tok::kw___constant: + case tok::kw___generic: + case tok::kw___read_only: + case tok::kw___read_write: + case tok::kw___write_only: + return true; + } +} + +// Determine if this is a GCC-style asm statement. +static bool isGCCAsmStatement(const Token &TokAfterAsm) { + return TokAfterAsm.is(tok::l_paren) || TokAfterAsm.is(tok::kw_goto) || + isTypeQualifier(TokAfterAsm); +} + /// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled, /// this routine is called to collect the tokens for an MS asm statement. /// @@ -392,6 +417,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { if (!InAsmComment && Tok.is(tok::l_brace)) { // Consume the opening brace. SkippedStartOfLine = Tok.isAtStartOfLine(); + AsmToks.push_back(Tok); EndLoc = ConsumeBrace(); BraceNesting++; LBraceLocs.push_back(EndLoc); @@ -416,15 +442,19 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { if (ExpLoc.first != FID || SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) { // If this is a single-line __asm, we're done, except if the next - // line begins with an __asm too, in which case we finish a comment + // line is MS-style asm too, in which case we finish a comment // if needed and then keep processing the next line as a single // line __asm. bool isAsm = Tok.is(tok::kw_asm); - if (SingleLineMode && !isAsm) + if (SingleLineMode && (!isAsm || isGCCAsmStatement(NextToken()))) break; // We're no longer in a comment. InAsmComment = false; if (isAsm) { + // If this is a new __asm {} block we want to process it seperately + // from the single-line __asm statements + if (PP.LookAhead(0).is(tok::l_brace)) + break; LineNo = SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second); SkippedStartOfLine = Tok.isAtStartOfLine(); } @@ -440,6 +470,11 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { BraceCount == (savedBraceCount + BraceNesting)) { // Consume the closing brace. SkippedStartOfLine = Tok.isAtStartOfLine(); + // Don't want to add the closing brace of the whole asm block + if (SingleLineMode || BraceNesting > 1) { + Tok.clearFlag(Token::LeadingSpace); + AsmToks.push_back(Tok); + } EndLoc = ConsumeBrace(); BraceNesting--; // Finish if all of the opened braces in the inline asm section were @@ -523,18 +558,22 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString)) return StmtError(); + TargetOptions TO = Actions.Context.getTargetInfo().getTargetOpts(); + std::string FeaturesStr = + llvm::join(TO.Features.begin(), TO.Features.end(), ","); + std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT)); // 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, "", "")); + TheTarget->createMCSubtargetInfo(TT, TO.CPU, FeaturesStr)); llvm::SourceMgr TempSrcMgr; llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr); - MOFI->InitMCObjectFileInfo(TheTriple, llvm::Reloc::Default, - llvm::CodeModel::Default, Ctx); + MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, llvm::CodeModel::Default, + Ctx); std::unique_ptr<llvm::MemoryBuffer> Buffer = llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>"); @@ -631,8 +670,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); SourceLocation AsmLoc = ConsumeToken(); - if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) && - !isTypeQualifier()) { + if (getLangOpts().AsmBlocks && !isGCCAsmStatement(Tok)) { msAsm = true; return ParseMicrosoftAsmStatement(AsmLoc); } @@ -652,6 +690,14 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { // Remember if this was a volatile asm. bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; + + // TODO: support "asm goto" constructs (PR#9295). + if (Tok.is(tok::kw_goto)) { + Diag(Tok, diag::err_asm_goto_not_supported_yet); + SkipUntil(tok::r_paren, StopAtSemi); + return StmtError(); + } + if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "asm"; SkipUntil(tok::r_paren, StopAtSemi); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index a4dcdb1e2a09..6cf7b6d3dc55 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -122,20 +122,15 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, return nullptr; } - ParamLists.push_back( - Actions.ActOnTemplateParameterList(CurTemplateDepthTracker.getDepth(), - ExportLoc, - TemplateLoc, LAngleLoc, - TemplateParams, RAngleLoc)); - + ExprResult OptionalRequiresClauseConstraintER; if (!TemplateParams.empty()) { isSpecialization = false; ++CurTemplateDepthTracker; if (TryConsumeToken(tok::kw_requires)) { - ExprResult ER = + OptionalRequiresClauseConstraintER = Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression()); - if (!ER.isUsable()) { + if (!OptionalRequiresClauseConstraintER.isUsable()) { // Skip until the semi-colon or a '}'. SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); TryConsumeToken(tok::semi); @@ -145,8 +140,15 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, } else { LastParamListWasEmpty = true; } + + ParamLists.push_back(Actions.ActOnTemplateParameterList( + CurTemplateDepthTracker.getDepth(), ExportLoc, TemplateLoc, LAngleLoc, + TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get())); } while (Tok.isOneOf(tok::kw_export, tok::kw_template)); + unsigned NewFlags = getCurScope()->getFlags() & ~Scope::TemplateParamScope; + ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization); + // Parse the actual template declaration. return ParseSingleDeclarationAfterTemplate(Context, ParsedTemplateInfo(&ParamLists, @@ -209,11 +211,15 @@ Parser::ParseSingleDeclarationAfterTemplate( if (Tok.is(tok::semi)) { ProhibitAttributes(prefixAttrs); DeclEnd = ConsumeToken(); + RecordDecl *AnonRecord = nullptr; Decl *Decl = Actions.ParsedFreeStandingDeclSpec( getCurScope(), AS, DS, TemplateInfo.TemplateParams ? *TemplateInfo.TemplateParams : MultiTemplateParamsArg(), - TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation); + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation, + AnonRecord); + assert(!AnonRecord && + "Anonymous unions/structs should not be valid with template"); DS.complete(Decl); return Decl; } @@ -280,7 +286,7 @@ Parser::ParseSingleDeclarationAfterTemplate( TemplateParameterLists FakedParamLists; FakedParamLists.push_back(Actions.ActOnTemplateParameterList( 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, None, - LAngleLoc)); + LAngleLoc, nullptr)); return ParseFunctionDefinition( DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists, @@ -631,7 +637,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { Actions.ActOnTemplateParameterList(Depth, SourceLocation(), TemplateLoc, LAngleLoc, TemplateParams, - RAngleLoc); + RAngleLoc, nullptr); // Grab a default argument (if available). // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before @@ -827,6 +833,7 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, } // Strip the initial '>' from the token. + Token PrevTok = Tok; if (RemainingToken == tok::equal && Next.is(tok::equal) && areTokensAdjacent(Tok, Next)) { // Join two adjacent '=' tokens into one, for cases like: @@ -843,6 +850,21 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, PP.getSourceManager(), getLangOpts())); + // The advance from '>>' to '>' in a ObjectiveC template argument list needs + // to be properly reflected in the token cache to allow correct interaction + // between annotation and backtracking. + if (ObjCGenericList && PrevTok.getKind() == tok::greatergreater && + RemainingToken == tok::greater && PP.IsPreviousCachedToken(PrevTok)) { + PrevTok.setKind(RemainingToken); + PrevTok.setLength(1); + // Break tok::greatergreater into two tok::greater but only add the second + // one in case the client asks to consume the last token. + if (ConsumeLastToken) + PP.ReplacePreviousCachedToken({PrevTok, Tok}); + else + PP.ReplacePreviousCachedToken({PrevTok}); + } + if (!ConsumeLastToken) { // Since we're not supposed to consume the '>' token, we need to push // this token and revert the current token back to the '>'. @@ -1061,7 +1083,7 @@ void Parser::AnnotateTemplateIdTokenAsType() { TemplateId->RAngleLoc); // Create the new "type" annotation token. Tok.setKind(tok::annot_typename); - setTypeAnnotation(Tok, Type.isInvalid() ? ParsedType() : Type.get()); + setTypeAnnotation(Tok, Type.isInvalid() ? nullptr : Type.get()); if (TemplateId->SS.isNotEmpty()) // it was a C++ qualified type name. Tok.setLocation(TemplateId->SS.getBeginLoc()); // End location stays the same @@ -1094,9 +1116,9 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { // followed by a token that terminates a template argument, such as ',', // '>', or (in some cases) '>>'. CXXScopeSpec SS; // nested-name-specifier, if present - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); - + ParsedTemplateArgument Result; SourceLocation EllipsisLoc; if (SS.isSet() && Tok.is(tok::kw_template)) { @@ -1117,11 +1139,10 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { // template argument. TemplateTy Template; if (isEndOfTemplateArgument(Tok) && - Actions.ActOnDependentTemplateName(getCurScope(), - SS, TemplateKWLoc, Name, - /*ObjectType=*/ ParsedType(), - /*EnteringContext=*/false, - Template)) + Actions.ActOnDependentTemplateName( + getCurScope(), SS, TemplateKWLoc, Name, + /*ObjectType=*/nullptr, + /*EnteringContext=*/false, Template)) Result = ParsedTemplateArgument(SS, Template, Name.StartLocation); } } else if (Tok.is(tok::identifier)) { @@ -1135,13 +1156,11 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { if (isEndOfTemplateArgument(Tok)) { bool MemberOfUnknownSpecialization; - TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, - /*hasTemplateKeyword=*/false, - Name, - /*ObjectType=*/ ParsedType(), - /*EnteringContext=*/false, - Template, - MemberOfUnknownSpecialization); + TemplateNameKind TNK = Actions.isTemplateName( + getCurScope(), SS, + /*hasTemplateKeyword=*/false, Name, + /*ObjectType=*/nullptr, + /*EnteringContext=*/false, Template, MemberOfUnknownSpecialization); if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) { // We have an id-expression that refers to a class template or // (C++0x) alias template. @@ -1352,7 +1371,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { // Append the current token at the end of the new token stream so that it // doesn't get lost. LPT.Toks.push_back(Tok); - PP.EnterTokenStream(LPT.Toks.data(), LPT.Toks.size(), true, false); + PP.EnterTokenStream(LPT.Toks, true); // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 6fbcfd9bd217..7703c33b8780 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -125,10 +125,11 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) { // Ok, we have a simple-type-specifier/typename-specifier followed by a '(', // or an identifier which doesn't resolve as anything. We need tentative // parsing... - - TentativeParsingAction PA(*this); - TPR = TryParseSimpleDeclaration(AllowForRangeDecl); - PA.Revert(); + + { + RevertingTentativeParsingAction PA(*this); + TPR = TryParseSimpleDeclaration(AllowForRangeDecl); + } // In case of an error, let the declaration parsing code handle it. if (TPR == TPResult::Error) @@ -329,10 +330,70 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() { return TPResult::Ambiguous; } -/// isCXXConditionDeclaration - Disambiguates between a declaration or an -/// expression for a condition of a if/switch/while/for statement. -/// If during the disambiguation process a parsing error is encountered, -/// the function returns true to let the declaration parsing code handle it. +struct Parser::ConditionDeclarationOrInitStatementState { + Parser &P; + bool CanBeExpression = true; + bool CanBeCondition = true; + bool CanBeInitStatement; + + ConditionDeclarationOrInitStatementState(Parser &P, bool CanBeInitStatement) + : P(P), CanBeInitStatement(CanBeInitStatement) {} + + void markNotExpression() { + CanBeExpression = false; + + if (CanBeCondition && CanBeInitStatement) { + // FIXME: Unify the parsing codepaths for condition variables and + // simple-declarations so that we don't need to eagerly figure out which + // kind we have here. (Just parse init-declarators until we reach a + // semicolon or right paren.) + RevertingTentativeParsingAction PA(P); + P.SkipUntil(tok::r_paren, tok::semi, StopBeforeMatch); + if (P.Tok.isNot(tok::r_paren)) + CanBeCondition = false; + if (P.Tok.isNot(tok::semi)) + CanBeInitStatement = false; + } + } + + bool markNotCondition() { + CanBeCondition = false; + return !CanBeInitStatement || !CanBeExpression; + } + + bool update(TPResult IsDecl) { + switch (IsDecl) { + case TPResult::True: + markNotExpression(); + return true; + case TPResult::False: + CanBeCondition = CanBeInitStatement = false; + return true; + case TPResult::Ambiguous: + return false; + case TPResult::Error: + CanBeExpression = CanBeCondition = CanBeInitStatement = false; + return true; + } + llvm_unreachable("unknown tentative parse result"); + } + + ConditionOrInitStatement result() const { + assert(CanBeExpression + CanBeCondition + CanBeInitStatement < 2 && + "result called but not yet resolved"); + if (CanBeExpression) + return ConditionOrInitStatement::Expression; + if (CanBeCondition) + return ConditionOrInitStatement::ConditionDecl; + if (CanBeInitStatement) + return ConditionOrInitStatement::InitStmtDecl; + return ConditionOrInitStatement::Error; + } +}; + +/// \brief Disambiguates between a declaration in a condition, a +/// simple-declaration in an init-statement, and an expression for +/// a condition of a if/switch statement. /// /// condition: /// expression @@ -341,47 +402,64 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() { /// [C++11] type-specifier-seq declarator braced-init-list /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression +/// simple-declaration: +/// decl-specifier-seq init-declarator-list[opt] ';' /// -bool Parser::isCXXConditionDeclaration() { - TPResult TPR = isCXXDeclarationSpecifier(); - if (TPR != TPResult::Ambiguous) - return TPR != TPResult::False; // Returns true for TPResult::True or - // TPResult::Error. - - // FIXME: Add statistics about the number of ambiguous statements encountered - // and how they were resolved (number of declarations+number of expressions). +/// Note that, unlike isCXXSimpleDeclaration, we must disambiguate all the way +/// to the ';' to disambiguate cases like 'int(x))' (an expression) from +/// 'int(x);' (a simple-declaration in an init-statement). +Parser::ConditionOrInitStatement +Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement) { + ConditionDeclarationOrInitStatementState State(*this, CanBeInitStatement); - // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. - // We need tentative parsing... + if (State.update(isCXXDeclarationSpecifier())) + return State.result(); - TentativeParsingAction PA(*this); + // It might be a declaration; we need tentative parsing. + RevertingTentativeParsingAction PA(*this); - // type-specifier-seq - TryConsumeDeclarationSpecifier(); + // FIXME: A tag definition unambiguously tells us this is an init-statement. + if (State.update(TryConsumeDeclarationSpecifier())) + return State.result(); assert(Tok.is(tok::l_paren) && "Expected '('"); - // declarator - TPR = TryParseDeclarator(false/*mayBeAbstract*/); + while (true) { + // Consume a declarator. + if (State.update(TryParseDeclarator(false/*mayBeAbstract*/))) + return State.result(); + + // Attributes, asm label, or an initializer imply this is not an expression. + // FIXME: Disambiguate properly after an = instead of assuming that it's a + // valid declaration. + if (Tok.isOneOf(tok::equal, tok::kw_asm, tok::kw___attribute) || + (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace))) { + State.markNotExpression(); + return State.result(); + } - // In case of an error, let the declaration parsing code handle it. - if (TPR == TPResult::Error) - TPR = TPResult::True; + // At this point, it can't be a condition any more, because a condition + // must have a brace-or-equal-initializer. + if (State.markNotCondition()) + return State.result(); - if (TPR == TPResult::Ambiguous) { - // '=' - // [GNU] simple-asm-expr[opt] attributes[opt] - if (Tok.isOneOf(tok::equal, tok::kw_asm, tok::kw___attribute)) - TPR = TPResult::True; - else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) - TPR = TPResult::True; - else - TPR = TPResult::False; - } + // A parenthesized initializer could be part of an expression or a + // simple-declaration. + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + SkipUntil(tok::r_paren, StopAtSemi); + } - PA.Revert(); + if (!TryConsumeToken(tok::comma)) + break; + } - assert(TPR == TPResult::True || TPR == TPResult::False); - return TPR == TPResult::True; + // We reached the end. If it can now be some kind of decl, then it is. + if (State.CanBeCondition && Tok.is(tok::r_paren)) + return ConditionOrInitStatement::ConditionDecl; + else if (State.CanBeInitStatement && Tok.is(tok::semi)) + return ConditionOrInitStatement::InitStmtDecl; + else + return ConditionOrInitStatement::Expression; } /// \brief Determine whether the next set of tokens contains a type-id. @@ -423,7 +501,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. // We need tentative parsing... - TentativeParsingAction PA(*this); + RevertingTentativeParsingAction PA(*this); // type-specifier-seq TryConsumeDeclarationSpecifier(); @@ -456,8 +534,6 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { TPR = TPResult::False; } - PA.Revert(); - assert(TPR == TPResult::True || TPR == TPResult::False); return TPR == TPResult::True; } @@ -508,7 +584,7 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, if (!Disambiguate && !getLangOpts().ObjC1) return CAK_AttributeSpecifier; - TentativeParsingAction PA(*this); + RevertingTentativeParsingAction PA(*this); // Opening brackets were checked for above. ConsumeBracket(); @@ -520,8 +596,6 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, bool IsAttribute = SkipUntil(tok::r_square); IsAttribute &= Tok.is(tok::r_square); - PA.Revert(); - return IsAttribute ? CAK_AttributeSpecifier : CAK_InvalidAttributeSpecifier; } @@ -542,8 +616,6 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, // A lambda cannot end with ']]', and an attribute must. bool IsAttribute = Tok.is(tok::r_square); - PA.Revert(); - if (IsAttribute) // Case 1: C++11 attribute. return CAK_AttributeSpecifier; @@ -564,7 +636,6 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, while (Tok.isNot(tok::r_square)) { if (Tok.is(tok::comma)) { // Case 1: Stray commas can only occur in attributes. - PA.Revert(); return CAK_AttributeSpecifier; } @@ -611,8 +682,6 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, } } - PA.Revert(); - if (IsAttribute) // Case 1: C++11 statement attribute. return CAK_AttributeSpecifier; @@ -833,7 +902,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // '(' abstract-declarator ')' if (Tok.isOneOf(tok::kw___attribute, tok::kw___declspec, tok::kw___cdecl, tok::kw___stdcall, tok::kw___fastcall, tok::kw___thiscall, - tok::kw___vectorcall, tok::kw___unaligned)) + tok::kw___vectorcall)) return TPResult::True; // attributes indicate declaration TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier); if (TPR != TPResult::Ambiguous) @@ -946,6 +1015,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_char: case tok::kw_const: case tok::kw_double: + case tok::kw___float128: case tok::kw_enum: case tok::kw_half: case tok::kw_float: @@ -987,6 +1057,8 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___pixel: case tok::kw___bool: case tok::kw__Atomic: +#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: +#include "clang/Basic/OpenCLImageTypes.def" case tok::kw___unknown_anytype: return TPResult::False; @@ -1317,7 +1389,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, Tok.getAnnotationRange(), SS); if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) { - TentativeParsingAction PA(*this); + RevertingTentativeParsingAction PA(*this); ConsumeToken(); ConsumeToken(); bool isIdentifier = Tok.is(tok::identifier); @@ -1325,7 +1397,6 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, if (!isIdentifier) TPR = isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); - PA.Revert(); if (isIdentifier || TPR == TPResult::True || TPR == TPResult::Error) @@ -1337,6 +1408,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, *HasMissingTypename = true; return TPResult::Ambiguous; } + + // FIXME: Fails to either revert or commit the tentative parse! } else { // Try to resolve the name. If it doesn't exist, assume it was // intended to name a type and keep disambiguating. @@ -1388,15 +1461,13 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // In Objective-C, we might have a protocol-qualified type. if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { // Tentatively parse the protocol qualifiers. - TentativeParsingAction PA(*this); + RevertingTentativeParsingAction PA(*this); ConsumeToken(); // The type token TPResult TPR = TryParseProtocolQualifiers(); bool isFollowedByParen = Tok.is(tok::l_paren); bool isFollowedByBrace = Tok.is(tok::l_brace); - PA.Revert(); - if (TPR == TPResult::Error) return TPResult::Error; @@ -1424,6 +1495,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_void: case tok::annot_decltype: if (NextToken().is(tok::l_paren)) @@ -1448,14 +1520,12 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, if (NextToken().isNot(tok::l_paren)) return TPResult::True; - TentativeParsingAction PA(*this); + RevertingTentativeParsingAction PA(*this); TPResult TPR = TryParseTypeofSpecifier(); bool isFollowedByParen = Tok.is(tok::l_paren); bool isFollowedByBrace = Tok.is(tok::l_brace); - PA.Revert(); - if (TPR == TPResult::Error) return TPResult::Error; @@ -1515,6 +1585,7 @@ bool Parser::isCXXDeclarationSpecifierAType() { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_void: case tok::kw___unknown_anytype: case tok::kw___auto_type: @@ -1594,7 +1665,7 @@ bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) { // ambiguities mentioned in 6.8, the resolution is to consider any construct // that could possibly be a declaration a declaration. - TentativeParsingAction PA(*this); + RevertingTentativeParsingAction PA(*this); ConsumeParen(); bool InvalidAsDeclaration = false; @@ -1618,8 +1689,6 @@ bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) { } } - PA.Revert(); - if (IsAmbiguous && TPR == TPResult::Ambiguous) *IsAmbiguous = true; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index ccefb3dd3f5d..f968f995d53f 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -491,6 +491,8 @@ void Parser::Initialize() { Ident_deprecated = nullptr; Ident_obsoleted = nullptr; Ident_unavailable = nullptr; + Ident_strict = nullptr; + Ident_replacement = nullptr; Ident__except = nullptr; @@ -545,7 +547,7 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof)) ConsumeToken(); - Result = DeclGroupPtrTy(); + Result = nullptr; switch (Tok.getKind()) { case tok::annot_pragma_unused: HandlePragmaUnused(); @@ -625,52 +627,54 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, if (PP.isCodeCompletionReached()) { cutOffParsing(); - return DeclGroupPtrTy(); + return nullptr; } Decl *SingleDecl = nullptr; switch (Tok.getKind()) { case tok::annot_pragma_vis: HandlePragmaVisibility(); - return DeclGroupPtrTy(); + return nullptr; case tok::annot_pragma_pack: HandlePragmaPack(); - return DeclGroupPtrTy(); + return nullptr; case tok::annot_pragma_msstruct: HandlePragmaMSStruct(); - return DeclGroupPtrTy(); + return nullptr; case tok::annot_pragma_align: HandlePragmaAlign(); - return DeclGroupPtrTy(); + return nullptr; case tok::annot_pragma_weak: HandlePragmaWeak(); - return DeclGroupPtrTy(); + return nullptr; case tok::annot_pragma_weakalias: HandlePragmaWeakAlias(); - return DeclGroupPtrTy(); + return nullptr; case tok::annot_pragma_redefine_extname: HandlePragmaRedefineExtname(); - return DeclGroupPtrTy(); + return nullptr; case tok::annot_pragma_fp_contract: HandlePragmaFPContract(); - return DeclGroupPtrTy(); + return nullptr; case tok::annot_pragma_opencl_extension: HandlePragmaOpenCLExtension(); - return DeclGroupPtrTy(); - case tok::annot_pragma_openmp: - return ParseOpenMPDeclarativeDirective(); + return nullptr; + case tok::annot_pragma_openmp: { + AccessSpecifier AS = AS_none; + return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs); + } case tok::annot_pragma_ms_pointers_to_members: HandlePragmaMSPointersToMembers(); - return DeclGroupPtrTy(); + return nullptr; case tok::annot_pragma_ms_vtordisp: HandlePragmaMSVtorDisp(); - return DeclGroupPtrTy(); + return nullptr; case tok::annot_pragma_ms_pragma: HandlePragmaMSPragma(); - return DeclGroupPtrTy(); + return nullptr; case tok::annot_pragma_dump: HandlePragmaDump(); - return DeclGroupPtrTy(); + return nullptr; case tok::semi: // Either a C++11 empty-declaration or attribute-declaration. SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(), @@ -681,10 +685,10 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::r_brace: Diag(Tok, diag::err_extraneous_closing_brace); ConsumeBrace(); - return DeclGroupPtrTy(); + return nullptr; case tok::eof: Diag(Tok, diag::err_expected_external_declaration); - return DeclGroupPtrTy(); + return nullptr; case tok::kw___extension__: { // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. @@ -712,7 +716,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, "top-level asm block"); if (Result.isInvalid()) - return DeclGroupPtrTy(); + return nullptr; SingleDecl = Actions.ActOnFileScopeAsmDecl(Result.get(), StartLoc, EndLoc); break; } @@ -723,7 +727,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, if (!getLangOpts().ObjC1) { Diag(Tok, diag::err_expected_external_declaration); ConsumeToken(); - return DeclGroupPtrTy(); + return nullptr; } SingleDecl = ParseObjCMethodDefinition(); break; @@ -732,7 +736,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, CurParsedObjCImpl? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace); cutOffParsing(); - return DeclGroupPtrTy(); + return nullptr; case tok::kw_using: case tok::kw_namespace: case tok::kw_typedef: @@ -796,8 +800,8 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw___if_exists: case tok::kw___if_not_exists: ParseMicrosoftIfExistsExternalDeclaration(); - return DeclGroupPtrTy(); - + return nullptr; + default: dont_know: // We can't tell whether this is a function-definition or declaration yet. @@ -876,15 +880,21 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, // may get this far before the problem becomes obvious. if (DS.hasTagDefinition() && DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_top_level)) - return DeclGroupPtrTy(); + return nullptr; // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { ProhibitAttributes(attrs); ConsumeToken(); - Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); + RecordDecl *AnonRecord = nullptr; + Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, + DS, AnonRecord); DS.complete(TheDecl); + if (AnonRecord) { + Decl* decls[] = {AnonRecord, TheDecl}; + return Actions.BuildDeclaratorGroup(decls, /*TypeMayContainAuto=*/false); + } return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -899,7 +909,7 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, !Tok.isObjCAtKeyword(tok::objc_protocol)) { Diag(Tok, diag::err_objc_unexpected_attr); SkipUntil(tok::semi); // FIXME: better skip? - return DeclGroupPtrTy(); + return nullptr; } DS.abort(); @@ -1034,6 +1044,12 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, D.complete(DP); D.getMutableDeclSpec().abort(); + if (SkipFunctionBodies && (!DP || Actions.canSkipFunctionBody(DP)) && + trySkippingFunctionBody()) { + BodyScope.Exit(); + return Actions.ActOnSkippedFunctionBody(DP); + } + CachedTokens Toks; LexTemplateFunctionForLateParsing(Toks); @@ -1126,6 +1142,13 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, return Res; } + if (SkipFunctionBodies && (!Res || Actions.canSkipFunctionBody(Res)) && + trySkippingFunctionBody()) { + BodyScope.Exit(); + Actions.ActOnSkippedFunctionBody(Res); + return Actions.ActOnFinishFunctionBody(Res, nullptr, false); + } + if (Tok.is(tok::kw_try)) return ParseFunctionTryBlock(Res, BodyScope); @@ -1400,7 +1423,7 @@ Parser::TryAnnotateName(bool IsAddressOfOperand, CXXScopeSpec SS; if (getLangOpts().CPlusPlus && - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) + ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext)) return ANK_Error; if (Tok.isNot(tok::identifier) || SS.isInvalid()) { @@ -1588,9 +1611,9 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { // simple-template-id SourceLocation TypenameLoc = ConsumeToken(); CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(), - /*EnteringContext=*/false, - nullptr, /*IsTypename*/ true)) + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, + /*EnteringContext=*/false, nullptr, + /*IsTypename*/ true)) return true; if (!SS.isSet()) { if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id) || @@ -1646,7 +1669,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { SourceLocation EndLoc = Tok.getLastLoc(); Tok.setKind(tok::annot_typename); - setTypeAnnotation(Tok, Ty.isInvalid() ? ParsedType() : Ty.get()); + setTypeAnnotation(Tok, Ty.isInvalid() ? nullptr : Ty.get()); Tok.setAnnotationEndLoc(EndLoc); Tok.setLocation(TypenameLoc); PP.AnnotateCachedTokens(Tok); @@ -1658,7 +1681,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { CXXScopeSpec SS; if (getLangOpts().CPlusPlus) - if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) + if (ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext)) return true; return TryAnnotateTypeOrScopeTokenAfterScopeSpec(EnteringContext, NeedType, @@ -1675,15 +1698,12 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext, if (Tok.is(tok::identifier)) { IdentifierInfo *CorrectedII = nullptr; // Determine whether the identifier is a type name. - if (ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), getCurScope(), - &SS, false, - NextToken().is(tok::period), - ParsedType(), - /*IsCtorOrDtorName=*/false, - /*NonTrivialTypeSourceInfo*/ true, - NeedType ? &CorrectedII - : nullptr)) { + if (ParsedType Ty = Actions.getTypeName( + *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS, + false, NextToken().is(tok::period), nullptr, + /*IsCtorOrDtorName=*/false, + /*NonTrivialTypeSourceInfo*/ true, + NeedType ? &CorrectedII : nullptr)) { // A FixIt was applied as a result of typo correction if (CorrectedII) Tok.setIdentifierInfo(CorrectedII); @@ -1734,12 +1754,11 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext, UnqualifiedId TemplateName; TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); bool MemberOfUnknownSpecialization; - if (TemplateNameKind TNK - = Actions.isTemplateName(getCurScope(), SS, - /*hasTemplateKeyword=*/false, TemplateName, - /*ObjectType=*/ ParsedType(), - EnteringContext, - Template, MemberOfUnknownSpecialization)) { + if (TemplateNameKind TNK = + Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, TemplateName, + /*ObjectType=*/nullptr, EnteringContext, + Template, MemberOfUnknownSpecialization)) { // Consume the identifier. ConsumeToken(); if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), @@ -1793,7 +1812,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { "Cannot be a type or scope token!"); CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) + if (ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext)) return true; if (SS.isEmpty()) return false; @@ -1897,7 +1916,7 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) { // Parse nested-name-specifier. if (getLangOpts().CPlusPlus) - ParseOptionalCXXScopeSpecifier(Result.SS, ParsedType(), + ParseOptionalCXXScopeSpecifier(Result.SS, nullptr, /*EnteringContext=*/false); // Check nested-name specifier. @@ -1908,8 +1927,8 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) { // Parse the unqualified-id. SourceLocation TemplateKWLoc; // FIXME: parsed, but unused. - if (ParseUnqualifiedId(Result.SS, false, true, true, ParsedType(), - TemplateKWLoc, Result.Name)) { + if (ParseUnqualifiedId(Result.SS, false, true, true, nullptr, TemplateKWLoc, + Result.Name)) { T.skipToEnd(); return true; } @@ -1990,12 +2009,12 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteModuleImport(ImportLoc, Path); cutOffParsing(); - return DeclGroupPtrTy(); + return nullptr; } Diag(Tok, diag::err_module_expected_ident); SkipUntil(tok::semi); - return DeclGroupPtrTy(); + return nullptr; } // Record this part of the module path. @@ -2013,14 +2032,14 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) { if (PP.hadModuleLoaderFatalFailure()) { // With a fatal failure in the module loader, we abort parsing. cutOffParsing(); - return DeclGroupPtrTy(); + return nullptr; } DeclResult Import = Actions.ActOnModuleImport(AtLoc, ImportLoc, Path); ExpectAndConsumeSemi(diag::err_module_expected_semi); if (Import.isInvalid()) - return DeclGroupPtrTy(); - + return nullptr; + return Actions.ConvertDeclToDeclGroup(Import.get()); } |