Updated the patch to use the LabelDecl machinery.
Note that there are a couple of issues with the diagnostics that I'm generating
(see the TODO comments.)
The first issue is that I currently diagnose jumping to an asm label from a
goto statement in ActOnGotoStmt, which means that we currently can't diagnose
the case where we first see the goto statement, generate an implicit label from
it, and later on see an asm block which defines a label with that name. The
reason why the proper diagnostic is hard is that I don't know where the right
place to perform it is. Note that we need access to the SourceLocation of the
GotoStmt and also to the SourceLocation of the place where the label is
declared in the asm block.
The second issue with the diagnostics is that as I'm generating the "use of
undeclared label" error, I only have access to the LabelDecl and its location,
which means that for example the diagnostic in t10 in test/Sema/ms-inline-asm.c
is misplaced.
Any help with fixing the above two issues is appreciated.
Also, I have tested most of the combinations of goto's, jumps and asm/non-asm
labels that I have thought of, but I may have missed something. If you see
cases for which I have not included a test case, please point them out!
http://reviews.llvm.org/D4589
Files:
include/clang/AST/Decl.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Parse/ParseStmtAsm.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/Parser/ms-inline-asm.c
test/Sema/ms-inline-asm.c
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -24,6 +24,7 @@
#include "clang/Basic/OperatorKinds.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
@@ -308,14 +309,19 @@
class LabelDecl : public NamedDecl {
void anchor() override;
LabelStmt *TheStmt;
+ SmallString<16> 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.
SourceLocation LocStart;
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 +341,12 @@
return SourceRange(LocStart, getLocation());
}
+ bool isMSAsmLabel() const { return MSAsmName.size() != 0; }
+ bool isResolvedMSAsmLabel() const { return isMSAsmLabel() && MSAsmNameResolved; }
+ void setMSAsmLabel(StringRef Name) { MSAsmName = 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: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4116,6 +4116,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<UnusedLabel>, DefaultIgnore;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -3156,6 +3156,9 @@
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: lib/Parse/ParseStmtAsm.cpp
===================================================================
--- lib/Parse/ParseStmtAsm.cpp
+++ lib/Parse/ParseStmtAsm.cpp
@@ -93,6 +93,18 @@
return Info.OpDecl;
}
+ StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM,
+ llvm::SMLoc Location,
+ bool Create) override {
+ const llvm::MemoryBuffer *LBuf =
+ LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(Location));
+ unsigned Offset = Location.getPointer() - LBuf->getBufferStart();
+ SourceLocation Loc = translateLocation(Offset);
+ 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,15 +145,7 @@
}
}
- void handleDiagnostic(const llvm::SMDiagnostic &D) {
- // 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();
-
+ SourceLocation translateLocation(unsigned Offset) {
// Figure out which token that offset points into.
const unsigned *TokOffsetPtr =
std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);
@@ -157,6 +161,19 @@
Loc = Tok.getLocation();
Loc = Loc.getLocWithOffset(Offset - TokOffset);
}
+ return Loc;
+ }
+
+ void handleDiagnostic(const llvm::SMDiagnostic &D) {
+ // 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();
+
+ SourceLocation Loc = translateLocation(Offset);
TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
}
};
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ 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) <<L->getDeclName();
}
Index: lib/Sema/SemaStmt.cpp
===================================================================
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -2353,6 +2353,15 @@
StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc,
SourceLocation LabelLoc,
LabelDecl *TheDecl) {
+ if (TheDecl->isMSAsmLabel()) {
+ // TODO Move this diagnostic elsewhere so that we get to examine the goto
+ // statements after we've seen all of the body of the current scope.
+ StmtResult error(StmtError(Diag(GotoLoc, diag::err_goto_ms_asm_label)
+ << TheDecl->getIdentifier()));
+ Diag(TheDecl->getLocation(), diag::note_goto_ms_asm_label)
+ << TheDecl->getIdentifier();
+ return error;
+ }
getCurFunction()->setHasBranchIntoScope();
TheDecl->markUsed(Context);
return new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc);
Index: lib/Sema/SemaStmtAsm.cpp
===================================================================
--- lib/Sema/SemaStmtAsm.cpp
+++ lib/Sema/SemaStmtAsm.cpp
@@ -15,13 +15,15 @@
#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"
#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/Support/Format.h"
using namespace clang;
using namespace sema;
@@ -513,3 +515,27 @@
Clobbers, EndLoc);
return NS;
}
+
+LabelDecl *Sema::GetOrCreateMSAsmLabel(StringRef ExternalLabelName,
+ SourceLocation Location,
+ bool AlwaysCreate) {
+ static uint32_t counter = 0;
+
+ 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 << llvm::format("__MSASMLABEL_.%" PRIu32 "__", counter++);
+ Label->setMSAsmLabel(OS.str());
+ }
+ if (AlwaysCreate)
+ Label->setMSAsmLabelResolved();
+
+ return Label;
+}
Index: test/CodeGen/mozilla-ms-inline-asm.c
===================================================================
--- test/CodeGen/mozilla-ms-inline-asm.c
+++ 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__
+// ^ 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__:
+// 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: test/CodeGen/ms-inline-asm.c
===================================================================
--- test/CodeGen/ms-inline-asm.c
+++ 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__:", "~{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__:\0A\09jmp {{.*}}__MSASMLABEL_.1__", "~{dirflag},~{fpsr},~{flags}"()
+}
+
+void label2() {
+ __asm {
+ jmp label
+ label:
+ }
+ // CHECK-LABEL: define void @label2
+ // CHECK: call void asm sideeffect inteldialect "jmp {{.*}}__MSASMLABEL_.2__\0A\09{{.*}}__MSASMLABEL_.2__:", "~{dirflag},~{fpsr},~{flags}"()
+}
+
+void label3() {
+ __asm {
+ label:
+ mov eax, label
+ }
+ // CHECK-LABEL: define void @label3
+ // CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.3__:\0A\09mov eax, {{.*}}__MSASMLABEL_.3__", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+}
Index: test/Parser/ms-inline-asm.c
===================================================================
--- test/Parser/ms-inline-asm.c
+++ 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: test/Sema/ms-inline-asm.c
===================================================================
--- test/Sema/ms-inline-asm.c
+++ test/Sema/ms-inline-asm.c
@@ -21,7 +21,7 @@
}
f();
__asm {
- mov eax, LENGTH bar // expected-error {{unable to lookup expression}}
+ mov eax, LENGTH bar // expected-error {{unable to lookup expression}} expected-error {{use of undeclared label 'bar'}}
}
f();
__asm {
@@ -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,12 +106,43 @@
}
__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 }
}
int y;
__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}}
+}
+
+/*
+// TODO: Fix the following diagnostics
+void t9() {
+ goto foo; // expected-xxxerror {{cannot jump from this goto statement to label 'foo' inside an inline assembly block}}
+ __asm {
+ foo: // expected-xxxnote {{inline assembly label 'foo' declared here}}
+ mov eax, 0
+ }
+}
+*/
+
+void t10() {
+// TODO: The diagnostic below has the wrong location, because we don't have a better location in CheckPoppedLabel
+foo: // expected-error {{use of undeclared label 'foo'}}
+ __asm mov eax, foo
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits