From: Denis Zobnin Date: Thu, 21 Apr 2016 10:59:18 +0000 (+0000) Subject: Correctly parse GCC-style asm line following MS-style asm line. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d804162fa113644d92c47dcd1b225b0ed726a422;p=clang Correctly parse GCC-style asm line following MS-style asm line. Quit parsing MS-style inline assembly if the following statement has GCC style. Enables compilation of code like void f() { __asm mov ebx, ecx __asm__("movl %ecx, %edx"); } Differential Revision: http://reviews.llvm.org/D18652 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@266976 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index cde0308816..04e7984734 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -27,6 +27,8 @@ def err_msasm_unable_to_create_target : Error< "MS-style inline assembly is not available: %0">; def err_gnu_inline_asm_disabled : Error< "GNU-style inline assembly is disabled">; +def err_asm_goto_not_supported_yet : Error< + "'asm goto' constructs are not supported yet">; } let CategoryName = "Parse Issue" in { diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 66406ba36e..6b586ddbbc 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1873,7 +1873,6 @@ private: bool isDeclarationSpecifier(bool DisambiguatingWithExpression = false); bool isTypeSpecifierQualifier(); - bool isTypeQualifier() const; /// 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 diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b06eda9d23..cbe3d91367 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -4255,27 +4255,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. diff --git a/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp index 99b164d973..00ed9ce381 100644 --- a/lib/Parse/ParseStmtAsm.cpp +++ b/lib/Parse/ParseStmtAsm.cpp @@ -335,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. /// @@ -415,11 +442,11 @@ 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; @@ -643,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); } @@ -664,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/test/CodeGen/inline-asm-mixed-style.c b/test/CodeGen/inline-asm-mixed-style.c new file mode 100644 index 0000000000..914a11d351 --- /dev/null +++ b/test/CodeGen/inline-asm-mixed-style.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple i386-unknown-unknown -fasm-blocks -fsyntax-only -verify %s -DCHECK_ASM_GOTO +// RUN: %clang_cc1 -triple i386-unknown-unknown -fasm-blocks -O0 -emit-llvm -S %s -o - | FileCheck %s + +void f() { + __asm mov eax, ebx + __asm mov ebx, ecx + __asm__("movl %ecx, %edx"); + // CHECK: movl %ebx, %eax + // CHECK: movl %ecx, %ebx + // CHECK: movl %ecx, %edx + + __asm mov eax, ebx + __asm volatile ("movl %ecx, %edx"); + // CHECK: movl %ebx, %eax + // CHECK: movl %ecx, %edx + + __asm mov eax, ebx + __asm const ("movl %ecx, %edx"); // expected-warning {{ignored const qualifier on asm}} + // CHECK: movl %ebx, %eax + // CHECK: movl %ecx, %edx + +#ifdef CHECK_ASM_GOTO + __asm volatile goto ("movl %ecx, %edx"); // expected-error {{'asm goto' constructs are not supported yet}} + + __asm mov eax, ebx + __asm goto ("movl %ecx, %edx"); // expected-error {{'asm goto' constructs are not supported yet}} +#endif +}