}
}
-/// 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.
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.
///
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;
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);
}
// 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);
--- /dev/null
+// 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
+}