diff options
Diffstat (limited to 'clang/lib/Parse/ParseStmtAsm.cpp')
-rw-r--r-- | clang/lib/Parse/ParseStmtAsm.cpp | 166 |
1 files changed, 88 insertions, 78 deletions
diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp index ea2c871d6a82..7d0818840a4f 100644 --- a/clang/lib/Parse/ParseStmtAsm.cpp +++ b/clang/lib/Parse/ParseStmtAsm.cpp @@ -220,9 +220,10 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, // Parse an optional scope-specifier if we're in C++. CXXScopeSpec SS; - if (getLangOpts().CPlusPlus) { - ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); - } + if (getLangOpts().CPlusPlus) + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, + /*ObjectHadErrors=*/false, + /*EnteringContext=*/false); // Require an identifier here. SourceLocation TemplateKWLoc; @@ -233,12 +234,13 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, Result = ParseCXXThis(); Invalid = false; } else { - Invalid = ParseUnqualifiedId(SS, - /*EnteringContext=*/false, - /*AllowDestructorName=*/false, - /*AllowConstructorName=*/false, - /*AllowDeductionGuide=*/false, - /*ObjectType=*/nullptr, &TemplateKWLoc, Id); + Invalid = + ParseUnqualifiedId(SS, /*ObjectType=*/nullptr, + /*ObjectHadErrors=*/false, + /*EnteringContext=*/false, + /*AllowDestructorName=*/false, + /*AllowConstructorName=*/false, + /*AllowDeductionGuide=*/false, &TemplateKWLoc, Id); // Perform the lookup. Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, IsUnevaluatedContext); @@ -349,31 +351,13 @@ 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. +bool Parser::isGCCAsmStatement(const Token &TokAfterAsm) const { + return TokAfterAsm.is(tok::l_paren) || isGNUAsmQualifier(TokAfterAsm); } -// 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); +bool Parser::isGNUAsmQualifier(const Token &TokAfterAsm) const { + return getGNUAsmQualifier(TokAfterAsm) != GNUAsmQualifiers::AQ_unspecified; } /// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled, @@ -631,8 +615,8 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { // Change to the Intel dialect. Parser->setAssemblerDialect(1); Parser->setTargetParser(*TargetParser.get()); - Parser->setParsingInlineAsm(true); - TargetParser->setParsingInlineAsm(true); + Parser->setParsingMSInlineAsm(true); + TargetParser->setParsingMSInlineAsm(true); ClangAsmParserCallback Callback(*this, AsmLoc, AsmString, AsmToks, TokOffsets); @@ -684,13 +668,41 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { ClobberRefs, Exprs, EndLoc); } +/// parseGNUAsmQualifierListOpt - Parse a GNU extended asm qualifier list. +/// asm-qualifier: +/// volatile +/// inline +/// goto +/// +/// asm-qualifier-list: +/// asm-qualifier +/// asm-qualifier-list asm-qualifier +bool Parser::parseGNUAsmQualifierListOpt(GNUAsmQualifiers &AQ) { + while (1) { + const GNUAsmQualifiers::AQ A = getGNUAsmQualifier(Tok); + if (A == GNUAsmQualifiers::AQ_unspecified) { + if (Tok.isNot(tok::l_paren)) { + Diag(Tok.getLocation(), diag::err_asm_qualifier_ignored); + SkipUntil(tok::r_paren, StopAtSemi); + return true; + } + return false; + } + if (AQ.setAsmQualifier(A)) + Diag(Tok.getLocation(), diag::err_asm_duplicate_qual) + << GNUAsmQualifiers::getQualifierName(A); + ConsumeToken(); + } + return false; +} + /// ParseAsmStatement - Parse a GNU extended asm statement. /// asm-statement: /// gnu-asm-statement /// ms-asm-statement /// /// [GNU] gnu-asm-statement: -/// 'asm' type-qualifier[opt] '(' asm-argument ')' ';' +/// 'asm' asm-qualifier-list[opt] '(' asm-argument ')' ';' /// /// [GNU] asm-argument: /// asm-string-literal @@ -712,34 +724,14 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { return ParseMicrosoftAsmStatement(AsmLoc); } - DeclSpec DS(AttrFactory); SourceLocation Loc = Tok.getLocation(); - ParseTypeQualifierListOpt(DS, AR_VendorAttributesParsed); - - // GNU asms accept, but warn, about type-qualifiers other than volatile. - if (DS.getTypeQualifiers() & DeclSpec::TQ_const) - Diag(Loc, diag::warn_asm_qualifier_ignored) << "const"; - if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) - Diag(Loc, diag::warn_asm_qualifier_ignored) << "restrict"; - // FIXME: Once GCC supports _Atomic, check whether it permits it here. - if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) - Diag(Loc, diag::warn_asm_qualifier_ignored) << "_Atomic"; - - // Remember if this was a volatile asm. - bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; - // Remember if this was a goto asm. - bool isGotoAsm = false; - - if (Tok.is(tok::kw_goto)) { - isGotoAsm = true; - ConsumeToken(); - } - - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after) << "asm"; - SkipUntil(tok::r_paren, StopAtSemi); + GNUAsmQualifiers GAQ; + if (parseGNUAsmQualifierListOpt(GAQ)) return StmtError(); - } + + if (GAQ.isGoto() && getLangOpts().SpeculativeLoadHardening) + Diag(Loc, diag::warn_slh_does_not_support_asm_goto); + BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); @@ -767,11 +759,10 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { if (Tok.is(tok::r_paren)) { // We have a simple asm expression like 'asm("foo")'. T.consumeClose(); - return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, - /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr, - Constraints, Exprs, AsmString.get(), - Clobbers, /*NumLabels*/ 0, - T.getCloseLocation()); + return Actions.ActOnGCCAsmStmt( + AsmLoc, /*isSimple*/ true, GAQ.isVolatile(), + /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr, Constraints, Exprs, + AsmString.get(), Clobbers, /*NumLabels*/ 0, T.getCloseLocation()); } // Parse Outputs, if present. @@ -781,12 +772,6 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { AteExtraColon = Tok.is(tok::coloncolon); ConsumeToken(); - if (!AteExtraColon && isGotoAsm && Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_asm_goto_cannot_have_output); - SkipUntil(tok::r_paren, StopAtSemi); - return StmtError(); - } - if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs)) return StmtError(); } @@ -835,7 +820,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { } } } - if (!isGotoAsm && (Tok.isNot(tok::r_paren) || AteExtraColon)) { + if (!GAQ.isGoto() && (Tok.isNot(tok::r_paren) || AteExtraColon)) { Diag(Tok, diag::err_expected) << tok::r_paren; SkipUntil(tok::r_paren, StopAtSemi); return StmtError(); @@ -868,16 +853,16 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { if (!TryConsumeToken(tok::comma)) break; } - } else if (isGotoAsm) { + } else if (GAQ.isGoto()) { Diag(Tok, diag::err_expected) << tok::colon; SkipUntil(tok::r_paren, StopAtSemi); return StmtError(); } T.consumeClose(); - return Actions.ActOnGCCAsmStmt( - AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(), - Constraints, Exprs, AsmString.get(), Clobbers, NumLabels, - T.getCloseLocation()); + return Actions.ActOnGCCAsmStmt(AsmLoc, false, GAQ.isVolatile(), NumOutputs, + NumInputs, Names.data(), Constraints, Exprs, + AsmString.get(), Clobbers, NumLabels, + T.getCloseLocation()); } /// ParseAsmOperands - Parse the asm-operands production as used by @@ -948,3 +933,28 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, return false; } } + +const char *Parser::GNUAsmQualifiers::getQualifierName(AQ Qualifier) { + switch (Qualifier) { + case AQ_volatile: return "volatile"; + case AQ_inline: return "inline"; + case AQ_goto: return "goto"; + case AQ_unspecified: return "unspecified"; + } + llvm_unreachable("Unknown GNUAsmQualifier"); +} + +Parser::GNUAsmQualifiers::AQ +Parser::getGNUAsmQualifier(const Token &Tok) const { + switch (Tok.getKind()) { + case tok::kw_volatile: return GNUAsmQualifiers::AQ_volatile; + case tok::kw_inline: return GNUAsmQualifiers::AQ_inline; + case tok::kw_goto: return GNUAsmQualifiers::AQ_goto; + default: return GNUAsmQualifiers::AQ_unspecified; + } +} +bool Parser::GNUAsmQualifiers::setAsmQualifier(AQ Qualifier) { + bool IsDuplicate = Qualifiers & Qualifier; + Qualifiers |= Qualifier; + return IsDuplicate; +} |