]> granicus.if.org Git - clang/commitdiff
ms-inline-asm: Scope inline asm labels to functions
authorEhsan Akhgari <ehsan.akhgari@gmail.com>
Mon, 22 Sep 2014 02:21:54 +0000 (02:21 +0000)
committerEhsan Akhgari <ehsan.akhgari@gmail.com>
Mon, 22 Sep 2014 02:21:54 +0000 (02:21 +0000)
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

15 files changed:
include/clang/AST/Decl.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/AST/Decl.cpp
lib/Parse/ParseStmtAsm.cpp
lib/Sema/JumpDiagnostics.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaStmt.cpp
lib/Sema/SemaStmtAsm.cpp
test/CodeGen/mozilla-ms-inline-asm.c
test/CodeGen/ms-inline-asm.c
test/CodeGen/ms-inline-asm.cpp
test/Parser/ms-inline-asm.c
test/Sema/ms-inline-asm.c

index 3aff0f5424b5d00908685c62db1ef1b7ff2953eb..8846d0ca8fb6dc1fbc1eef1f4c937f071207817b 100644 (file)
@@ -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; }
index 559bf62fd8c70c296cd1c05573b42e0e4eab803d..27661c17b736e971a8c6d1ba780ae5d29dcf7e83 100644 (file)
@@ -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<UnusedLabel>, DefaultIgnore;
 
index 0e5ed350a77784bde913f9dcca9a8ca0380671ce..d3c539b9a2d36e0f5fbc94846f006e0fdc26ff80 100644 (file)
@@ -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<StringRef> Clobbers,
                             ArrayRef<Expr*> Exprs,
                             SourceLocation EndLoc);
+  LabelDecl *GetOrCreateMSAsmLabel(StringRef ExternalLabelName,
+                                   SourceLocation Location,
+                                   bool AlwaysCreate);
 
   VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType,
                                   SourceLocation StartLoc,
index cc7c11ca6ef37d95b134e063187e6bd37ea33283..aec7059490c83954221d75a79ec9e2a175bd5a28 100644 (file)
@@ -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 {
index be3d79e22310d9374074b54ccc786e8f9be5a57e..35e2e6294f83ea356120faa81e8e348766b1af6d 100644 (file)
@@ -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();
   }
 };
index 255845282dfa151a092ecf5a5ec6da70516e1057..fd75c02bb1ed30650a8db0a2be200514659eee5b 100644 (file)
@@ -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<GotoStmt>(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);
 }
index 69a4356b450e20e79ecd3ca0c905a2c96944e923..7ecd41697d6ff5f5c7468460b57ef0e2c0aeea7d 100644 (file)
@@ -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),
index 535e33a2b6e605a2561876665383c1c12962dd36..ae79720e38317bec91165b070eab31a4a0815da5 100644 (file)
@@ -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) <<L->getDeclName();
 }
 
index 8d2a3258b10b41a1a8f8d0e720d112300b1b676e..464206eafe31b8192b6c6e1c9bea8ced15ab2e2c 100644 (file)
@@ -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;
 }
index 5aa1a2c86a91a49dad929c0a7e8ef8783efc6b54..dc50e87b589b9296ab2e01f801d3137c6161696a 100644 (file)
@@ -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<Expr*> 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;
+}
index 0f541d70fcddd89a9f5c84d62c3961d56996b02a..b8b7a2d677dd7e98380ab2cc72fae4ab696bbdec 100644 (file)
@@ -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
index 0a7ac1104304ac5bfe7800e44a05832a25e9f13a..3e6ebc8f077facb61cd2d750fc5832ff95525bba 100644 (file)
@@ -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}"()
+}
index 65e59d6b947996cab3946cf5349d310ba0d0f90c..03d971e698b5321f12f1aeebf8c14cd0ad12c2e9 100644 (file)
@@ -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();
+}
+
index 646f547e328f4c8013058a38ce396afbfca1c2b8..72c96c3715d95373d8a32433a7116e55c1e9e8f1 100644 (file)
@@ -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}}
index 358b0bd4543ed2adea05f69a6f4b9eefceedef58..6eac769505430a0216c9294f32d508c719da52a2 100644 (file)
@@ -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'}}
+}