Index: cfe/trunk/include/clang/AST/Decl.h =================================================================== --- cfe/trunk/include/clang/AST/Decl.h +++ cfe/trunk/include/clang/AST/Decl.h @@ -308,6 +308,8 @@ 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 @@ 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 @@ 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: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -4133,6 +4133,10 @@ 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; Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -699,7 +699,10 @@ /// \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 @@ ArrayRef Clobbers, ArrayRef Exprs, SourceLocation EndLoc); + LabelDecl *GetOrCreateMSAsmLabel(StringRef ExternalLabelName, + SourceLocation Location, + bool AlwaysCreate); VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, SourceLocation StartLoc, Index: cfe/trunk/lib/AST/Decl.cpp =================================================================== --- cfe/trunk/lib/AST/Decl.cpp +++ cfe/trunk/lib/AST/Decl.cpp @@ -3709,6 +3709,13 @@ 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: cfe/trunk/lib/Parse/ParseStmtAsm.cpp =================================================================== --- cfe/trunk/lib/Parse/ParseStmtAsm.cpp +++ cfe/trunk/lib/Parse/ParseStmtAsm.cpp @@ -93,6 +93,15 @@ 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 @@ } } - 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 @@ 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: cfe/trunk/lib/Sema/JumpDiagnostics.cpp =================================================================== --- cfe/trunk/lib/Sema/JumpDiagnostics.cpp +++ cfe/trunk/lib/Sema/JumpDiagnostics.cpp @@ -84,6 +84,7 @@ 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 @@ // 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::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: cfe/trunk/lib/Sema/Sema.cpp =================================================================== --- cfe/trunk/lib/Sema/Sema.cpp +++ cfe/trunk/lib/Sema/Sema.cpp @@ -98,6 +98,7 @@ InitDictionaryWithObjectsMethod(nullptr), ArrayAllocObjectsMethod(nullptr), DictAllocObjectsMethod(nullptr), + MSAsmLabelNameCounter(0), GlobalNewDeleteDeclared(false), TUKind(TUKind), NumSFINAEErrors(0), Index: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -1517,8 +1517,14 @@ 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(); } Index: cfe/trunk/lib/Sema/SemaStmt.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaStmt.cpp +++ cfe/trunk/lib/Sema/SemaStmt.cpp @@ -432,7 +432,11 @@ 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: cfe/trunk/lib/Sema/SemaStmtAsm.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaStmtAsm.cpp +++ cfe/trunk/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 @@ 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 @@ 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: cfe/trunk/test/CodeGen/mozilla-ms-inline-asm.c =================================================================== --- cfe/trunk/test/CodeGen/mozilla-ms-inline-asm.c +++ cfe/trunk/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 @@ // 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: cfe/trunk/test/CodeGen/ms-inline-asm.c =================================================================== --- cfe/trunk/test/CodeGen/ms-inline-asm.c +++ cfe/trunk/test/CodeGen/ms-inline-asm.c @@ -240,7 +240,7 @@ 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 @@ } // 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: cfe/trunk/test/CodeGen/ms-inline-asm.cpp =================================================================== --- cfe/trunk/test/CodeGen/ms-inline-asm.cpp +++ cfe/trunk/test/CodeGen/ms-inline-asm.cpp @@ -122,3 +122,20 @@ // 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: cfe/trunk/test/Parser/ms-inline-asm.c =================================================================== --- cfe/trunk/test/Parser/ms-inline-asm.c +++ cfe/trunk/test/Parser/ms-inline-asm.c @@ -48,6 +48,9 @@ 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: cfe/trunk/test/Sema/ms-inline-asm.c =================================================================== --- cfe/trunk/test/Sema/ms-inline-asm.c +++ cfe/trunk/test/Sema/ms-inline-asm.c @@ -29,7 +29,7 @@ } 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 @@ } 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 @@ } __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 @@ 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'}} +}