diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1255,6 +1255,34 @@ Query for this feature with ``__has_extension(blocks)``. +ASM Goto with Output Constraints +================================ + +In addition to the functionality provided by `GCC's extended +assembly``_, clang +supports output constraints with the `goto` form. + +The goto form of GCC's extended assembly allows the programmer to branch to a C +label from within an inline assembly block. Clang extends this behavior by +allowing the programmer to use output constriants: + +.. code-block:: c++ + + int foo(int x) { + int y; + asm goto("# %0 %1 %l2" : "=r"(y) : "r"(x) : : err); + return y; + err: + return -1; + } + +It's important to note that outputs are valid only on the "fallthrough" branch. +Using outputs on an indirect branch may result in undefined behavior. For +example, in the function above, use of the value assigned to `y` in the `err` +block is undefined behavior. + +Query for this feature with ``__has_extension(gnu_asm_goto_with_outputs)``. + Objective-C Features ==================== diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -3029,7 +3029,7 @@ } IdentifierInfo *getLabelIdentifier(unsigned i) const { - return Names[i + NumInputs]; + return Names[i + NumOutputs + NumInputs]; } AddrLabelExpr *getLabelExpr(unsigned i) const; @@ -3040,11 +3040,11 @@ using labels_const_range = llvm::iterator_range; labels_iterator begin_labels() { - return &Exprs[0] + NumInputs; + return &Exprs[0] + NumOutputs + NumInputs; } labels_iterator end_labels() { - return &Exprs[0] + NumInputs + NumLabels; + return &Exprs[0] + NumOutputs + NumInputs + NumLabels; } labels_range labels() { @@ -3052,11 +3052,11 @@ } const_labels_iterator begin_labels() const { - return &Exprs[0] + NumInputs; + return &Exprs[0] + NumOutputs + NumInputs; } const_labels_iterator end_labels() const { - return &Exprs[0] + NumInputs + NumLabels; + return &Exprs[0] + NumOutputs + NumInputs + NumLabels; } labels_const_range labels() const { diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -252,6 +252,7 @@ EXTENSION(pragma_clang_attribute_namespaces, true) EXTENSION(pragma_clang_attribute_external_declaration, true) EXTENSION(gnu_asm, LangOpts.GNUAsm) +EXTENSION(gnu_asm_goto_with_outputs, LangOpts.GNUAsm) #undef EXTENSION #undef FEATURE diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -457,7 +457,7 @@ } AddrLabelExpr *GCCAsmStmt::getLabelExpr(unsigned i) const { - return cast(Exprs[i + NumInputs]); + return cast(Exprs[i + NumOutputs + NumInputs]); } StringRef GCCAsmStmt::getLabelName(unsigned i) const { @@ -523,7 +523,7 @@ for (unsigned i = 0, e = getNumLabels(); i != e; ++i) if (getLabelName(i) == SymbolicName) - return i + getNumInputs(); + return i + getNumOutputs() + getNumInputs(); // Not found. return -1; diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp --- a/clang/lib/Analysis/UninitializedValues.cpp +++ b/clang/lib/Analysis/UninitializedValues.cpp @@ -475,6 +475,7 @@ void VisitCallExpr(CallExpr *ce); void VisitDeclRefExpr(DeclRefExpr *dr); void VisitDeclStmt(DeclStmt *ds); + void VisitGCCAsmStmt(GCCAsmStmt *as); void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS); void VisitObjCMessageExpr(ObjCMessageExpr *ME); void VisitOMPExecutableDirective(OMPExecutableDirective *ED); @@ -760,6 +761,16 @@ } } +void TransferFunctions::VisitGCCAsmStmt(GCCAsmStmt *as) { + // An "asm goto" statement is a terminator that may initialize some variables. + if (!as->isAsmGoto()) + return; + + for (const auto &o : as->outputs()) + if (const VarDecl *VD = findVar(o).getDecl()) + vals[VD] = Initialized; +} + void TransferFunctions::VisitObjCMessageExpr(ObjCMessageExpr *ME) { // If the Objective-C message expression is an implicit no-return that // is not modeled in the CFG, set the tracked dataflow values to Unknown. @@ -797,6 +808,10 @@ if (Optional cs = I.getAs()) tf.Visit(const_cast(cs->getStmt())); } + CFGTerminator terminator = block->getTerminator(); + if (GCCAsmStmt *as = dyn_cast_or_null(terminator.getStmt())) + if (as->isAsmGoto()) + tf.Visit(as); return vals.updateValueVectorWithScratch(block); } diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2211,13 +2211,6 @@ Constraints += InputConstraint; } - // Append the "input" part of inout constraints last. - for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) { - ArgTypes.push_back(InOutArgTypes[i]); - Args.push_back(InOutArgs[i]); - } - Constraints += InOutConstraints; - // Labels SmallVector Transfer; llvm::BasicBlock *Fallthrough = nullptr; @@ -2225,7 +2218,7 @@ if (const auto *GS = dyn_cast(&S)) { IsGCCAsmGoto = GS->isAsmGoto(); if (IsGCCAsmGoto) { - for (auto *E : GS->labels()) { + for (const auto *E : GS->labels()) { JumpDest Dest = getJumpDestForLabel(E->getLabel()); Transfer.push_back(Dest.getBlock()); llvm::BlockAddress *BA = @@ -2236,11 +2229,17 @@ Constraints += ','; Constraints += 'X'; } - StringRef Name = "asm.fallthrough"; - Fallthrough = createBasicBlock(Name); + Fallthrough = createBasicBlock("asm.fallthrough"); } } + // Append the "input" part of inout constraints last. + for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) { + ArgTypes.push_back(InOutArgTypes[i]); + Args.push_back(InOutArgs[i]); + } + Constraints += InOutConstraints; + // Clobbers for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) { StringRef Clobber = S.getClobber(i); @@ -2287,9 +2286,9 @@ if (IsGCCAsmGoto) { llvm::CallBrInst *Result = Builder.CreateCallBr(IA, Fallthrough, Transfer, Args); + EmitBlock(Fallthrough); UpdateAsmCallInst(cast(*Result), HasSideEffect, ReadOnly, ReadNone, S, ResultRegTypes, *this, RegResults); - EmitBlock(Fallthrough); } else { llvm::CallInst *Result = Builder.CreateCall(IA, Args, getBundlesForFunclet(IA)); diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp --- a/clang/lib/Parse/ParseStmtAsm.cpp +++ b/clang/lib/Parse/ParseStmtAsm.cpp @@ -781,12 +781,6 @@ 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(); } diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -478,10 +478,10 @@ // Look for the correct constraint index. unsigned ConstraintIdx = Piece.getOperandNo(); - // Labels are the last in the Exprs list. - if (NS->isAsmGoto() && ConstraintIdx >= NS->getNumInputs()) - continue; unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs(); + // Labels are the last in the Exprs list. + if (NS->isAsmGoto() && ConstraintIdx >= NumOperands) + continue; // Look for the (ConstraintIdx - NumOperands + 1)th constraint with // modifier '+'. if (ConstraintIdx >= NumOperands) { diff --git a/clang/test/Analysis/uninit-asm-goto.cpp b/clang/test/Analysis/uninit-asm-goto.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/uninit-asm-goto.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -std=c++11 -Wuninitialized -verify %s +// expected-no-diagnostics + +int test1(int x) { + int y; + asm goto("# %0 %1 %2" : "=r"(y) : "r"(x) : : err); + return y; + err: + return -1; +} diff --git a/clang/test/CodeGen/asm-goto.c b/clang/test/CodeGen/asm-goto.c --- a/clang/test/CodeGen/asm-goto.c +++ b/clang/test/CodeGen/asm-goto.c @@ -2,19 +2,104 @@ // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O0 -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -triple i386-pc-linux-gnu -O0 -emit-llvm %s -o - | FileCheck %s -int foo(int cond) -{ +int test1(int cond) { + // CHECK-LABEL: define i32 @test1( // CHECK: callbr void asm sideeffect // CHECK: to label %asm.fallthrough [label %label_true, label %loop] - // CHECK: asm.fallthrough: - asm volatile goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop); + // CHECK-LABEL: asm.fallthrough: asm volatile goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop); + asm volatile goto("testl %0, %0; jne %l2;" :: "r"(cond)::label_true, loop); // CHECK: callbr void asm sideeffect // CHECK: to label %asm.fallthrough1 [label %label_true, label %loop] - // CHECK: asm.fallthrough1: + // CHECK-LABEL: asm.fallthrough1: return 0; loop: return 0; label_true: return 1; } + +int test2(int cond) { + // CHECK-LABEL: define i32 @test2( + // CHECK: callbr i32 asm sideeffect + // CHECK: to label %asm.fallthrough [label %label_true, label %loop] + // CHECK-LABEL: asm.fallthrough: + asm volatile goto("testl %0, %0; jne %l2;" : "=r"(cond) : "r"(cond) :: label_true, loop); + asm volatile goto("testl %0, %0; jne %l3;" : "=r"(cond) : "r"(cond) :: label_true, loop); + // CHECK: callbr i32 asm sideeffect + // CHECK: to label %asm.fallthrough1 [label %label_true, label %loop] + // CHECK-LABEL: asm.fallthrough1: + return 0; +loop: + return 0; +label_true: + return 1; +} + +int test3(int out1, int out2) { + // CHECK-LABEL: define i32 @test3( + // CHECK: callbr { i32, i32 } asm sideeffect + // CHECK: to label %asm.fallthrough [label %label_true, label %loop] + // CHECK-LABEL: asm.fallthrough: + asm volatile goto("testl %0, %0; jne %l3;" : "=r"(out1), "=r"(out2) : "r"(out1) :: label_true, loop); + asm volatile goto("testl %0, %0; jne %l4;" : "=r"(out1), "=r"(out2) : "r"(out1) :: label_true, loop); + // CHECK: callbr { i32, i32 } asm sideeffect + // CHECK: to label %asm.fallthrough2 [label %label_true, label %loop] + // CHECK-LABEL: asm.fallthrough2: + return 0; +loop: + return 0; +label_true: + return 1; +} + +int test4(int out1, int out2) { + // CHECK-LABEL: define i32 @test4( + // CHECK: callbr { i32, i32 } asm sideeffect "jne ${3:l}", "={si},={di},r,X,X,0,1 + // CHECK: to label %asm.fallthrough [label %label_true, label %loop] + // CHECK-LABEL: asm.fallthrough: + if (out1 < out2) + asm volatile goto("jne %l3" : "+S"(out1), "+D"(out2) : "r"(out1) :: label_true, loop); + else + asm volatile goto("jne %l5" : "+S"(out1), "+D"(out2) : "r"(out1), "r"(out2) :: label_true, loop); + // CHECK: callbr { i32, i32 } asm sideeffect "jne ${5:l}", "={si},={di},r,r,X,X,0,1 + // CHECK: to label %asm.fallthrough2 [label %label_true, label %loop] + // CHECK-LABEL: asm.fallthrough2: + return out1 + out2; +loop: + return -1; +label_true: + return -2; +} + +int test5(int addr, int size, int limit) { + // CHECK-LABEL: define i32 @test5( + // CHECK: callbr i32 asm "add $1,$0 ; jc ${3:l} ; cmp $2,$0 ; ja ${3:l} ; ", "=r,imr,imr,X,0 + // CHECK: to label %asm.fallthrough [label %t_err] + // CHECK-LABEL: asm.fallthrough: + asm goto( + "add %1,%0 ; " + "jc %l[t_err] ; " + "cmp %2,%0 ; " + "ja %l[t_err] ; " + : "+r" (addr) + : "g" (size), "g" (limit) + : : t_err); + return 0; +t_err: + return 1; +} + +int test6(int out1) { + // CHECK-LABEL: define i32 @test6( + // CHECK: callbr i32 asm sideeffect "testl $0, $0; testl $1, $1; jne ${2:l}", "={si},r,X,X,0,{{.*}} i8* blockaddress(@test6, %label_true), i8* blockaddress(@test6, %landing) + // CHECK: to label %asm.fallthrough [label %label_true, label %landing] + // CHECK-LABEL: asm.fallthrough: + // CHECK-LABEL: landing: + int out2 = 42; + asm volatile goto("testl %0, %0; testl %1, %1; jne %l2" : "+S"(out2) : "r"(out1) :: label_true, landing); +landing: + return out1 + out2; +label_true: + return -2; +} diff --git a/clang/test/Parser/asm-goto.c b/clang/test/Parser/asm-goto.c --- a/clang/test/Parser/asm-goto.c +++ b/clang/test/Parser/asm-goto.c @@ -4,13 +4,13 @@ #if !__has_extension(gnu_asm) #error Extension 'gnu_asm' should be available by default #endif - +#if !__has_extension(gnu_asm_goto_with_outputs) +#error Extension 'gnu_asm_goto_with_outputs' should be available by default +#endif int a, b, c, d, e, f, g, h, i, j, k, l; -void -fgoto1 (void) -{ +void test(void) { __asm__ volatile goto ("" :: [a] "r" (a), [b] "r" (b), [c] "r" (c), [d] "r" (d), [e] "r" (e), [f] "r" (f), [g] "r" (g), [h] "r" (h), @@ -20,9 +20,7 @@ lab2: return; } -void -fgoto2 (void) -{ +void test2(void) { __asm__ volatile goto ("" :: [a] "r,m" (a), [b] "r,m" (b), [c] "r,m" (c), [d] "r,m" (d), [e] "r,m" (e), [f] "r,m" (f), [g] "r,m" (g), [h] "r,m" (h), @@ -31,14 +29,33 @@ lab: return; } -int zoo () -{ +int test3(int x) { + __asm__ volatile goto ("decl %0; jnz %l[a]" + : "=r" (x) : "m" (x) : "memory" : a); +a: + return -x; +} + +int test4(int x) { + int y; + if (x > 42) + __asm__ volatile goto ("decl %0; jnz %l[a]" + : "=r" (x), "=r" (y) : "m" (x) : "memory" : a); + else + __asm__ volatile goto ("decl %0; jnz %l[b]" + : "=r" (x), "=r" (y) : "m" (x) : "memory" : b); + x = y + 42; +a: + return -x; +b: + return +x; +} + +int test5(void) { int x,cond,*e; // expected-error@+1 {{expected ')'}} asm ("mov %[e], %[e]" : : [e] "rm" (*e)::a) - // expected-error@+1 {{'asm goto' cannot have output constraints}} - asm goto ("decl %0; jnz %l[a]" :"=r"(x): "m"(x) : "memory" : a); - // expected-error@+1 {{expected identifie}} + // expected-error@+1 {{expected identifier}} asm goto ("decl %0;" :: "m"(x) : "memory" : ); // expected-error@+1 {{expected ':'}} asm goto ("decl %0;" :: "m"(x) : "memory" ); @@ -55,3 +72,25 @@ loop: return 0; } + +int test6(int y) { + int x,cond,*e; + // expected-error@+1 {{expected ')'}} + asm ("mov %[e], %[e]" : "=r" (y) : [e] "rm" (*e), "r" (y) :: a) + // expected-error@+1 {{expected identifier}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory" :); + // expected-error@+1 {{expected ':'}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory"); + // expected-error@+1 {{use of undeclared label 'x'}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory" : x); + // expected-error@+1 {{use of undeclared label 'b'}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory" : b); + // expected-error@+1 {{invalid operand number in inline asm string}} + asm goto ("testl %0, %0; jne %l5;" : "=r" (y) : "r" (cond), "r" (y) :: label_true, loop); + // expected-error@+1 {{unknown symbolic operand name in inline assembly string}} + asm goto ("decl %0; jnz %l[b]" : "=r" (y) : "m" (x), "r" (y) : "memory" : a); +label_true: +loop: +a: + return 0; +} diff --git a/clang/test/Parser/asm-goto.cpp b/clang/test/Parser/asm-goto.cpp --- a/clang/test/Parser/asm-goto.cpp +++ b/clang/test/Parser/asm-goto.cpp @@ -1,14 +1,54 @@ // RUN: %clang_cc1 -triple i386-pc-linux-gnu -fsyntax-only -verify -std=c++11 %s // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -verify -std=c++11 %s -int zoo () -{ +int a, b, c, d, e, f, g, h, i, j, k, l; + +void test1(void) { + __asm__ volatile goto ("" + :: [a] "r" (a), [b] "r" (b), [c] "r" (c), [d] "r" (d), + [e] "r" (e), [f] "r" (f), [g] "r" (g), [h] "r" (h), + [i] "r" (i), [j] "r" (j), [k] "r" (k), [l] "r" (l) + ::lab1,lab2); +lab1: return; +lab2: return; +} + +void test2(void) { + __asm__ volatile goto ("" + :: [a] "r,m" (a), [b] "r,m" (b), [c] "r,m" (c), [d] "r,m" (d), + [e] "r,m" (e), [f] "r,m" (f), [g] "r,m" (g), [h] "r,m" (h), + [i] "r,m" (i), [j] "r,m" (j), [k] "r,m" (k), [l] "r,m" (l) + :: lab); + lab: return; +} + +int test3(int x) { + __asm__ volatile goto ("decl %0; jnz %l[a]" + : "=r" (x) : "m" (x) : "memory" : a); +a: + return -x; +} + +int test4(int x) { + int y; + if (x > 42) + __asm__ volatile goto ("decl %0; jnz %l[a]" + : "=r" (x), "=r" (y) : "m" (x) : "memory" : a); + else + __asm__ volatile goto ("decl %0; jnz %l[b]" + : "=r" (x), "=r" (y) : "m" (x) : "memory" : b); + x = y + 42; +a: + return -x; +b: + return +x; +} + +int test5(void) { int x,cond,*e; // expected-error@+1 {{expected ')'}} asm ("mov %[e], %[e]" : : [e] "rm" (*e)::a) - // expected-error@+1 {{'asm goto' cannot have output constraints}} - asm goto ("decl %0; jnz %l[a]" :"=r"(x): "m"(x) : "memory" : a); - // expected-error@+1 {{expected identifie}} + // expected-error@+1 {{expected identifier}} asm goto ("decl %0;" :: "m"(x) : "memory" : ); // expected-error@+1 {{expected ':'}} asm goto ("decl %0;" :: "m"(x) : "memory" ); @@ -26,28 +66,24 @@ return 0; } - -int a, b, c, d, e, f, g, h, i, j, k, l; - -void -fgoto1 (void) -{ - __asm__ volatile goto ("" - :: [a] "r" (a), [b] "r" (b), [c] "r" (c), [d] "r" (d), - [e] "r" (e), [f] "r" (f), [g] "r" (g), [h] "r" (h), - [i] "r" (i), [j] "r" (j), [k] "r" (k), [l] "r" (l) - ::lab1,lab2); -lab1: return; -lab2: return; -} - -void -fgoto2 (void) -{ - __asm__ volatile goto ("" - :: [a] "r,m" (a), [b] "r,m" (b), [c] "r,m" (c), [d] "r,m" (d), - [e] "r,m" (e), [f] "r,m" (f), [g] "r,m" (g), [h] "r,m" (h), - [i] "r,m" (i), [j] "r,m" (j), [k] "r,m" (k), [l] "r,m" (l) - :: lab); - lab: return; +int test6(int y) { + int x,cond,*e; + // expected-error@+1 {{expected ')'}} + asm ("mov %[e], %[e]" : "=r" (y) : [e] "rm" (*e), "r" (y) :: a) + // expected-error@+1 {{expected identifier}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory" :); + // expected-error@+1 {{expected ':'}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory"); + // expected-error@+1 {{use of undeclared label 'x'}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory" : x); + // expected-error@+1 {{use of undeclared label 'b'}} + asm goto ("decl %0;" : "=r" (y) : "m" (x), "r" (y) : "memory" : b); + // expected-error@+1 {{invalid operand number in inline asm string}} + asm goto ("testl %0, %0; jne %l5;" : "=r" (y) : "r" (cond), "r" (y) :: label_true, loop); + // expected-error@+1 {{unknown symbolic operand name in inline assembly string}} + asm goto ("decl %0; jnz %l[b]" : "=r" (y) : "m" (x), "r" (y) : "memory" : a); +label_true: +loop: +a: + return 0; } diff --git a/clang/test/Sema/asm-goto.cpp b/clang/test/Sema/asm-goto.cpp --- a/clang/test/Sema/asm-goto.cpp +++ b/clang/test/Sema/asm-goto.cpp @@ -1,38 +1,38 @@ // RUN: %clang_cc1 %s -triple i386-pc-linux-gnu -verify -fsyntax-only // RUN: %clang_cc1 %s -triple x86_64-pc-linux-gnu -verify -fsyntax-only -struct NonTrivial { - ~NonTrivial(); +struct S { + ~S(); int f(int); private: int k; }; -void JumpDiagnostics(int n) { +void test1(int n) { // expected-error@+1 {{cannot jump from this goto statement to its label}} goto DirectJump; // expected-note@+1 {{jump bypasses variable with a non-trivial destructor}} - NonTrivial tnp1; + S s1; DirectJump: // expected-error@+1 {{cannot jump from this asm goto statement to one of its possible targets}} asm goto("jmp %l0;" ::::Later); // expected-note@+1 {{jump bypasses variable with a non-trivial destructor}} - NonTrivial tnp2; + S s2; // expected-note@+1 {{possible target of asm goto statement}} Later: return; } -struct S { ~S(); }; -void foo(int a) { +struct T { ~T(); }; +void test2(int a) { if (a) { FOO: // expected-note@+2 {{jump exits scope of variable with non-trivial destructor}} // expected-note@+1 {{jump exits scope of variable with non-trivial destructor}} - S s; + T t; void *p = &&BAR; // expected-error@+1 {{cannot jump from this asm goto statement to one of its possible targets}} - asm goto("jmp %l0;" ::::BAR); + asm goto("jmp %l0;" ::::BAR); // expected-error@+1 {{cannot jump from this indirect goto statement to one of its possible targets}} goto *p; p = &&FOO; @@ -45,9 +45,7 @@ return; } - -//Asm goto: -int test16(int n) +int test3(int n) { // expected-error@+2 {{cannot jump from this asm goto statement to one of its possible targets}} // expected-error@+1 {{cannot jump from this asm goto statement to one of its possible targets}}