From: Ehsan Akhgari Date: Mon, 22 Sep 2014 02:21:54 +0000 (+0000) Subject: ms-inline-asm: Scope inline asm labels to functions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d88b0e1b7f200280079aba91b0dc1736d8bc1a11;p=clang ms-inline-asm: Scope inline asm labels to functions Summary: This fixes PR20023. In order to implement this scoping rule, we piggy back on the existing LabelDecl machinery, by creating LabelDecl's that will carry the "internal" name of the inline assembly label, which we will rewrite the asm label to. Reviewers: rnk Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D4589 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@218230 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 3aff0f5424..8846d0ca8f 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -308,6 +308,8 @@ inline raw_ostream &operator<<(raw_ostream &OS, const NamedDecl &ND) { class LabelDecl : public NamedDecl { void anchor() override; LabelStmt *TheStmt; + StringRef MSAsmName; + bool MSAsmNameResolved; /// LocStart - For normal labels, this is the same as the main declaration /// label, i.e., the location of the identifier; for GNU local labels, /// this is the location of the __label__ keyword. @@ -315,7 +317,10 @@ class LabelDecl : public NamedDecl { LabelDecl(DeclContext *DC, SourceLocation IdentL, IdentifierInfo *II, LabelStmt *S, SourceLocation StartL) - : NamedDecl(Label, DC, IdentL, II), TheStmt(S), LocStart(StartL) {} + : NamedDecl(Label, DC, IdentL, II), + TheStmt(S), + MSAsmNameResolved(false), + LocStart(StartL) {} public: static LabelDecl *Create(ASTContext &C, DeclContext *DC, @@ -335,6 +340,12 @@ public: return SourceRange(LocStart, getLocation()); } + bool isMSAsmLabel() const { return MSAsmName.size() != 0; } + bool isResolvedMSAsmLabel() const { return isMSAsmLabel() && MSAsmNameResolved; } + void setMSAsmLabel(StringRef Name); + StringRef getMSAsmLabel() const { return MSAsmName; } + void setMSAsmLabelResolved() { MSAsmNameResolved = true; } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Label; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 559bf62fd8..27661c17b7 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4133,6 +4133,10 @@ def warn_missing_braces : Warning< def err_redefinition_of_label : Error<"redefinition of label %0">; def err_undeclared_label_use : Error<"use of undeclared label %0">; +def err_goto_ms_asm_label : Error< + "cannot jump from this goto statement to label %0 inside an inline assembly block">; +def note_goto_ms_asm_label : Note< + "inline assembly label %0 declared here">; def warn_unused_label : Warning<"unused label %0">, InGroup, DefaultIgnore; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 0e5ed350a7..d3c539b9a2 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -699,7 +699,10 @@ public: /// \brief will hold 'respondsToSelector:' Selector RespondsToSelectorSel; - + + /// \brief counter for internal MS Asm label names. + unsigned MSAsmLabelNameCounter; + /// A flag to remember whether the implicit forms of operator new and delete /// have been declared. bool GlobalNewDeleteDeclared; @@ -3156,6 +3159,9 @@ public: ArrayRef Clobbers, ArrayRef Exprs, SourceLocation EndLoc); + LabelDecl *GetOrCreateMSAsmLabel(StringRef ExternalLabelName, + SourceLocation Location, + bool AlwaysCreate); VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, SourceLocation StartLoc, diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index cc7c11ca6e..aec7059490 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3709,6 +3709,13 @@ LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) { SourceLocation()); } +void LabelDecl::setMSAsmLabel(StringRef Name) { + char *Buffer = new (getASTContext(), 1) char[Name.size() + 1]; + memcpy(Buffer, Name.data(), Name.size()); + Buffer[Name.size()] = '\0'; + MSAsmName = Buffer; +} + void ValueDecl::anchor() { } bool ValueDecl::isWeak() const { diff --git a/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp index be3d79e223..35e2e6294f 100644 --- a/lib/Parse/ParseStmtAsm.cpp +++ b/lib/Parse/ParseStmtAsm.cpp @@ -93,6 +93,15 @@ public: return Info.OpDecl; } + StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM, + llvm::SMLoc Location, + bool Create) override { + SourceLocation Loc = translateLocation(LSM, Location); + LabelDecl *Label = + TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create); + return Label->getMSAsmLabel(); + } + bool LookupInlineAsmField(StringRef Base, StringRef Member, unsigned &Offset) override { return TheParser.getActions().LookupInlineAsmField(Base, Member, Offset, @@ -133,14 +142,13 @@ private: } } - void handleDiagnostic(const llvm::SMDiagnostic &D) { + SourceLocation translateLocation(const llvm::SourceMgr &LSM, llvm::SMLoc SMLoc) { // Compute an offset into the inline asm buffer. // FIXME: This isn't right if .macro is involved (but hopefully, no // real-world code does that). - const llvm::SourceMgr &LSM = *D.getSourceMgr(); const llvm::MemoryBuffer *LBuf = - LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); - unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart(); + LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc)); + unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart(); // Figure out which token that offset points into. const unsigned *TokOffsetPtr = @@ -157,6 +165,12 @@ private: Loc = Tok.getLocation(); Loc = Loc.getLocWithOffset(Offset - TokOffset); } + return Loc; + } + + void handleDiagnostic(const llvm::SMDiagnostic &D) { + const llvm::SourceMgr &LSM = *D.getSourceMgr(); + SourceLocation Loc = translateLocation(LSM, D.getLoc()); TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage(); } }; diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index 255845282d..fd75c02bb1 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -84,6 +84,7 @@ private: void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, unsigned JumpDiag, unsigned JumpDiagWarning, unsigned JumpDiagCXX98Compat); + void CheckGotoStmt(GotoStmt *GS); unsigned GetDeepestCommonScope(unsigned A, unsigned B); }; @@ -489,10 +490,14 @@ void JumpScopeChecker::VerifyJumps() { // With a goto, if (GotoStmt *GS = dyn_cast(Jump)) { - CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(), - diag::err_goto_into_protected_scope, - diag::ext_goto_into_protected_scope, - diag::warn_cxx98_compat_goto_into_protected_scope); + // The label may not have a statement if it's coming from inline MS ASM. + if (GS->getLabel()->getStmt()) { + CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(), + diag::err_goto_into_protected_scope, + diag::ext_goto_into_protected_scope, + diag::warn_cxx98_compat_goto_into_protected_scope); + } + CheckGotoStmt(GS); continue; } @@ -789,6 +794,15 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, } } +void JumpScopeChecker::CheckGotoStmt(GotoStmt *GS) { + if (GS->getLabel()->isMSAsmLabel()) { + S.Diag(GS->getGotoLoc(), diag::err_goto_ms_asm_label) + << GS->getLabel()->getIdentifier(); + S.Diag(GS->getLabel()->getLocation(), diag::note_goto_ms_asm_label) + << GS->getLabel()->getIdentifier(); + } +} + void Sema::DiagnoseInvalidJumps(Stmt *Body) { (void)JumpScopeChecker(Body, *this); } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 69a4356b45..7ecd41697d 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -98,6 +98,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, InitDictionaryWithObjectsMethod(nullptr), ArrayAllocObjectsMethod(nullptr), DictAllocObjectsMethod(nullptr), + MSAsmLabelNameCounter(0), GlobalNewDeleteDeclared(false), TUKind(TUKind), NumSFINAEErrors(0), diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 535e33a2b6..ae79720e38 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1517,8 +1517,14 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { static void CheckPoppedLabel(LabelDecl *L, Sema &S) { // Verify that we have no forward references left. If so, there was a goto // or address of a label taken, but no definition of it. Label fwd - // definitions are indicated with a null substmt. - if (L->getStmt() == nullptr) + // definitions are indicated with a null substmt which is also not a resolved + // MS inline assembly label name. + bool Diagnose = false; + if (L->isMSAsmLabel()) + Diagnose = !L->isResolvedMSAsmLabel(); + else + Diagnose = L->getStmt() == nullptr; + if (Diagnose) S.Diag(L->getLocation(), diag::err_undeclared_label_use) <getDeclName(); } diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 8d2a3258b1..464206eafe 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -432,7 +432,11 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, TheDecl->setStmt(LS); if (!TheDecl->isGnuLocal()) { TheDecl->setLocStart(IdentLoc); - TheDecl->setLocation(IdentLoc); + if (!TheDecl->isMSAsmLabel()) { + // Don't update the location of MS ASM labels. These will result in + // a diagnostic, and changing the location here will mess that up. + TheDecl->setLocation(IdentLoc); + } } return LS; } diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index 5aa1a2c86a..dc50e87b58 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/lib/Sema/SemaStmtAsm.cpp @@ -15,6 +15,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" @@ -520,6 +521,7 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, ArrayRef Exprs, SourceLocation EndLoc) { bool IsSimple = (NumOutputs != 0 || NumInputs != 0); + getCurFunction()->setHasBranchProtectedScope(); MSAsmStmt *NS = new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, /*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs, @@ -527,3 +529,31 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, Clobbers, EndLoc); return NS; } + +LabelDecl *Sema::GetOrCreateMSAsmLabel(StringRef ExternalLabelName, + SourceLocation Location, + bool AlwaysCreate) { + LabelDecl* Label = LookupOrCreateLabel(PP.getIdentifierInfo(ExternalLabelName), + Location); + + if (!Label->isMSAsmLabel()) { + // Otherwise, insert it, but only resolve it if we have seen the label itself. + std::string InternalName; + llvm::raw_string_ostream OS(InternalName); + // Create an internal name for the label. The name should not be a valid mangled + // name, and should be unique. We use a dot to make the name an invalid mangled + // name. + OS << "__MSASMLABEL_." << MSAsmLabelNameCounter++ << "__" << ExternalLabelName; + Label->setMSAsmLabel(OS.str()); + } + if (AlwaysCreate) { + // The label might have been created implicitly from a previously encountered + // goto statement. So, for both newly created and looked up labels, we mark + // them as resolved. + Label->setMSAsmLabelResolved(); + } + // Adjust their location for being able to generate accurate diagnostics. + Label->setLocation(Location); + + return Label; +} diff --git a/test/CodeGen/mozilla-ms-inline-asm.c b/test/CodeGen/mozilla-ms-inline-asm.c index 0f541d70fc..b8b7a2d677 100644 --- a/test/CodeGen/mozilla-ms-inline-asm.c +++ b/test/CodeGen/mozilla-ms-inline-asm.c @@ -3,6 +3,8 @@ // Some test cases for MS inline asm support from Mozilla code base. +void invoke_copy_to_stack() {} + void invoke(void* that, unsigned methodIndex, unsigned paramCount, void* params) { @@ -18,24 +20,25 @@ void invoke(void* that, unsigned methodIndex, // CHECK: call void asm sideeffect inteldialect // CHECK: mov edx,dword ptr $1 // CHECK: test edx,edx -// CHECK: jz noparams +// CHECK: jz {{[^_]*}}__MSASMLABEL_.0__noparams +// ^ Can't use {{.*}} here because the matching is greedy. // CHECK: mov eax,edx // CHECK: shl eax,$$3 // CHECK: sub esp,eax // CHECK: mov ecx,esp // CHECK: push dword ptr $0 -// CHECK: call invoke_copy_to_stack -// CHECK: noparams: -// CHECK: mov ecx,dword ptr $2 +// CHECK: call dword ptr $2 +// CHECK: {{.*}}__MSASMLABEL_.0__noparams: +// CHECK: mov ecx,dword ptr $3 // CHECK: push ecx // CHECK: mov edx,[ecx] -// CHECK: mov eax,dword ptr $3 +// CHECK: mov eax,dword ptr $4 // CHECK: call dword ptr[edx+eax*$$4] // CHECK: mov esp,ebp // CHECK: pop ebp // CHECK: ret -// CHECK: "=*m,*m,*m,*m,~{eax},~{ebp},~{ecx},~{edx},~{flags},~{esp},~{dirflag},~{fpsr},~{flags}" -// CHECK: (i8** %8, i32* %7, i8** %5, i32* %6) +// CHECK: "=*m,*m,*m,*m,*m,~{eax},~{ebp},~{ecx},~{edx},~{flags},~{esp},~{dirflag},~{fpsr},~{flags}" +// CHECK: (i8** %8, i32* %7, void (...)* bitcast (void ()* @invoke_copy_to_stack to void (...)*), i8** %5, i32* %6) // CHECK: ret void __asm { mov edx,paramCount diff --git a/test/CodeGen/ms-inline-asm.c b/test/CodeGen/ms-inline-asm.c index 0a7ac11043..3e6ebc8f07 100644 --- a/test/CodeGen/ms-inline-asm.c +++ b/test/CodeGen/ms-inline-asm.c @@ -240,7 +240,7 @@ void t23() { the_label: } // CHECK: t23 -// CHECK: call void asm sideeffect inteldialect "the_label:", "~{dirflag},~{fpsr},~{flags}"() +// CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.0__the_label:", "~{dirflag},~{fpsr},~{flags}"() } void t24_helper(void) {} @@ -517,3 +517,30 @@ void xgetbv() { } // CHECK-LABEL: define void @xgetbv() // CHECK: call void asm sideeffect inteldialect "xgetbv", "~{eax},~{edx},~{dirflag},~{fpsr},~{flags}"() + +void label1() { + __asm { + label: + jmp label + } + // CHECK-LABEL: define void @label1 + // CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.1__label:\0A\09jmp {{.*}}__MSASMLABEL_.1__label", "~{dirflag},~{fpsr},~{flags}"() +} + +void label2() { + __asm { + jmp label + label: + } + // CHECK-LABEL: define void @label2 + // CHECK: call void asm sideeffect inteldialect "jmp {{.*}}__MSASMLABEL_.2__label\0A\09{{.*}}__MSASMLABEL_.2__label:", "~{dirflag},~{fpsr},~{flags}"() +} + +void label3() { + __asm { + label: + mov eax, label + } + // CHECK-LABEL: define void @label3 + // CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.3__label:\0A\09mov eax, {{.*}}__MSASMLABEL_.3__label", "~{eax},~{dirflag},~{fpsr},~{flags}"() +} diff --git a/test/CodeGen/ms-inline-asm.cpp b/test/CodeGen/ms-inline-asm.cpp index 65e59d6b94..03d971e698 100644 --- a/test/CodeGen/ms-inline-asm.cpp +++ b/test/CodeGen/ms-inline-asm.cpp @@ -122,3 +122,20 @@ void t7_using() { // CHECK-LABEL: define void @_Z8t7_usingv // CHECK: call void asm sideeffect inteldialect "mov eax, [eax].4", "~{eax},~{dirflag},~{fpsr},~{flags}"() } + +void t8() { + __asm some_label: + // CHECK-LABEL: define void @_Z2t8v() + // CHECK: call void asm sideeffect inteldialect "L__MSASMLABEL_.1__some_label:", "~{dirflag},~{fpsr},~{flags}"() + struct A { + static void g() { + __asm jmp some_label ; This should jump forwards + __asm some_label: + __asm nop + // CHECK-LABEL: define internal void @_ZZ2t8vEN1A1gEv() + // CHECK: call void asm sideeffect inteldialect "jmp L__MSASMLABEL_.2__some_label\0A\09L__MSASMLABEL_.2__some_label:\0A\09nop", "~{dirflag},~{fpsr},~{flags}"() + } + }; + A::g(); +} + diff --git a/test/Parser/ms-inline-asm.c b/test/Parser/ms-inline-asm.c index 646f547e32..72c96c3715 100644 --- a/test/Parser/ms-inline-asm.c +++ b/test/Parser/ms-inline-asm.c @@ -48,6 +48,9 @@ void t10() { void t11() { do { __asm mov eax, 0 __asm { __asm mov edx, 1 } } while(0); } +void t12() { + __asm jmp label // expected-error {{use of undeclared label 'label'}} +} int t_fail() { // expected-note {{to match this}} __asm __asm { // expected-error 2 {{expected}} expected-note {{to match this}} diff --git a/test/Sema/ms-inline-asm.c b/test/Sema/ms-inline-asm.c index 358b0bd454..6eac769505 100644 --- a/test/Sema/ms-inline-asm.c +++ b/test/Sema/ms-inline-asm.c @@ -29,7 +29,7 @@ void f() { } f(); __asm { - mov eax, TYPE bar // expected-error {{unable to lookup expression}} + mov eax, TYPE bar // expected-error {{unable to lookup expression}} expected-error {{use of undeclared label 'bar'}} } } @@ -80,9 +80,10 @@ typedef struct { } A; void t3() { - __asm { mov eax, [eax] UndeclaredId } // expected-error {{unknown token in expression}} + __asm { mov eax, [eax] UndeclaredId } // expected-error {{unknown token in expression}} expected-error {{use of undeclared label 'UndeclaredId'}} // FIXME: Only emit one diagnostic here. + // expected-error@+3 {{use of undeclared label 'A'}} // expected-error@+2 {{unexpected type name 'A': expected expression}} // expected-error@+1 {{unknown token in expression}} __asm { mov eax, [eax] A } @@ -105,7 +106,7 @@ void test_operand_size() { } __declspec(naked) int t5(int x) { // expected-note {{attribute is here}} - asm { movl eax, x } // expected-error {{parameter references not allowed in naked functions}} + asm { movl eax, x } // expected-error {{parameter references not allowed in naked functions}} expected-error {{use of undeclared label 'x'}} asm { retl } } @@ -114,3 +115,36 @@ __declspec(naked) int t6(int x) { asm { mov eax, y } // No error. asm { ret } } + +void t7() { + __asm { + foo: // expected-note {{inline assembly label 'foo' declared here}} + mov eax, 0 + } + goto foo; // expected-error {{cannot jump from this goto statement to label 'foo' inside an inline assembly block}} +} + +void t8() { + __asm foo: // expected-note {{inline assembly label 'foo' declared here}} + __asm mov eax, 0 + goto foo; // expected-error {{cannot jump from this goto statement to label 'foo' inside an inline assembly block}} +} + +void t9() { + goto foo; // expected-error {{cannot jump from this goto statement to label 'foo' inside an inline assembly block}} + __asm { + foo: // expected-note {{inline assembly label 'foo' declared here}} + mov eax, 0 + } +} + +void t10() { + goto foo; // expected-error {{cannot jump from this goto statement to label 'foo' inside an inline assembly block}} + __asm foo: // expected-note {{inline assembly label 'foo' declared here}} + __asm mov eax, 0 +} + +void t11() { +foo: + __asm mov eax, foo // expected-error {{use of undeclared label 'foo'}} +}