aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2009-03-13 17:38:01 +0000
committerChris Lattner <sabre@nondot.org>2009-03-13 17:38:01 +0000
commit810f6d5d6223adaab0ccf0139f40de6484ad1bb5 (patch)
tree8c2283a32d43ceaaabee09ca1e692e300b905690
parentecdd84147c0765caa999ddc22dde25b42712bb4d (diff)
introduce a new -fheinous-gnu-extensions flag that enables really
really horrible extensions that are disabled by default but that can be accepted by -fheinous-gnu-extensions (but which always emit a warning when enabled). As our first instance of this, implement PR3788/PR3794, which allows non-lvalues in inline asms in contexts where lvalues are required. bleh. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66910 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--Driver/clang.cpp7
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.def7
-rw-r--r--include/clang/Basic/LangOptions.h3
-rw-r--r--lib/CodeGen/CGStmt.cpp7
-rw-r--r--lib/Sema/SemaStmt.cpp39
-rw-r--r--test/Sema/heinous-extensions-off.c10
-rw-r--r--test/Sema/heinous-extensions-on.c10
7 files changed, 76 insertions, 7 deletions
diff --git a/Driver/clang.cpp b/Driver/clang.cpp
index 171e4ecb31..b33f3443e5 100644
--- a/Driver/clang.cpp
+++ b/Driver/clang.cpp
@@ -480,6 +480,11 @@ EnableBlocks("fblocks", llvm::cl::desc("enable the 'blocks' language feature"),
llvm::cl::ZeroOrMore);
static llvm::cl::opt<bool>
+EnableHeinousExtensions("fheinous-gnu-extensions",
+ llvm::cl::desc("enable GNU extensions that you really really shouldn't use"),
+ llvm::cl::ValueDisallowed, llvm::cl::Hidden);
+
+static llvm::cl::opt<bool>
ObjCNonFragileABI("fobjc-nonfragile-abi",
llvm::cl::desc("enable objective-c's nonfragile abi"));
@@ -647,6 +652,8 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
if (Freestanding)
Options.Freestanding = 1;
+ if (EnableHeinousExtensions)
+ Options.HeinousExtensions = 1;
Options.MathErrno = MathErrno;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def
index 0267cfc10b..8938a7ae63 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.def
+++ b/include/clang/Basic/DiagnosticSemaKinds.def
@@ -1205,6 +1205,13 @@ DIAG(err_asm_invalid_type_in_input, ERROR,
"invalid type %0 in asm input for constraint '%1'")
DIAG(err_asm_unknown_register_name, ERROR,
"unknown register name '%0' in asm")
+DIAG(err_invalid_asm_cast_lvalue, ERROR,
+ "invalid use of a cast in a inline asm context requiring an l-value:"
+ " remove the cast or build with -fheinous-gnu-extensions")
+DIAG(warn_invalid_asm_cast_lvalue, WARNING,
+ "invalid use of a cast in a inline asm context requiring an l-value:"
+ " accepted due to -fheinous-gnu-extensions, but clang may remove support"
+ " for this in the future")
DIAG(err_invalid_conversion_between_vectors, ERROR,
"invalid conversion between vector type %0 and %1 of different size")
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index fcfe0ca1e9..f0a583c3d3 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -57,6 +57,8 @@ public:
unsigned MathErrno : 1; // Math functions must respect errno
// (modulo the platform support).
+ unsigned HeinousExtensions : 1; // Extensions that we really don't like and
+ // may be ripped out at any time.
private:
unsigned GC : 2; // Objective-C Garbage Collection modes. We declare
// this enum as unsigned because MSVC insists on making enums
@@ -75,6 +77,7 @@ public:
CXXOperatorNames = PascalStrings = Boolean = WritableStrings = 0;
Exceptions = NeXTRuntime = Freestanding = 0;
LaxVectorConversions = 1;
+ HeinousExtensions = 0;
// FIXME: The default should be 1.
ThreadsafeStatics = 0;
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index fddc547fd3..91aa88569e 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -730,6 +730,7 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S,
if (Ty->isSingleValueType()) {
Arg = EmitScalarExpr(InputExpr);
} else {
+ InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
LValue Dest = EmitLValue(InputExpr);
uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty);
@@ -744,6 +745,7 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S,
}
}
} else {
+ InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
LValue Dest = EmitLValue(InputExpr);
Arg = Dest.getAddress();
ConstraintStr += '*';
@@ -799,7 +801,10 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Simplify the output constraint.
OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1, Target);
- LValue Dest = EmitLValue(S.getOutputExpr(i));
+ const Expr *OutExpr = S.getOutputExpr(i);
+ OutExpr = OutExpr->IgnoreParenNoopCasts(getContext());
+
+ LValue Dest = EmitLValue(OutExpr);
const llvm::Type *DestValueType =
cast<llvm::PointerType>(Dest.getAddress()->getType())->getElementType();
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 96e59f0f82..39f21f853a 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -641,9 +641,7 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
return StmtError(Diag(VD->getLocation(),
diag::err_non_variable_decl_in_for));
} else {
- Expr::isLvalueResult lval = cast<Expr>(First)->isLvalue(Context);
-
- if (lval != Expr::LV_Valid)
+ if (cast<Expr>(First)->isLvalue(Context) != Expr::LV_Valid)
return StmtError(Diag(First->getLocStart(),
diag::err_selector_element_not_lvalue)
<< First->getSourceRange());
@@ -833,6 +831,36 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
}
+/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
+/// ignore "noop" casts in places where an lvalue is required by an inline asm.
+/// We emulate this behavior when -fheinous-gnu-extensions is specified, but
+/// provide a strong guidance to not use it.
+///
+/// This method checks to see if the argument is an acceptable l-value and
+/// returns false if it is a case we can handle.
+static bool CheckAsmLValue(const Expr *E, Sema &S) {
+ if (E->isLvalue(S.Context) == Expr::LV_Valid)
+ return false; // Cool, this is an lvalue.
+
+ // Okay, this is not an lvalue, but perhaps it is the result of a cast that we
+ // are supposed to allow.
+ const Expr *E2 = E->IgnoreParenNoopCasts(S.Context);
+ if (E != E2 && E2->isLvalue(S.Context) == Expr::LV_Valid) {
+ if (!S.getLangOptions().HeinousExtensions)
+ S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
+ << E->getSourceRange();
+ else
+ S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
+ << E->getSourceRange();
+ // Accept, even if we emitted an error diagnostic.
+ return false;
+ }
+
+ // None of the above, just randomly invalid non-lvalue.
+ return true;
+}
+
+
Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
bool IsSimple,
bool IsVolatile,
@@ -875,8 +903,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
// Check that the output exprs are valid lvalues.
ParenExpr *OutputExpr = cast<ParenExpr>(Exprs[i]);
- Expr::isLvalueResult Result = OutputExpr->isLvalue(Context);
- if (Result != Expr::LV_Valid) {
+ if (CheckAsmLValue(OutputExpr, *this)) {
return StmtError(Diag(OutputExpr->getSubExpr()->getLocStart(),
diag::err_asm_invalid_lvalue_in_output)
<< OutputExpr->getSubExpr()->getSourceRange());
@@ -909,7 +936,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
// Only allow void types for memory constraints.
if ((info & TargetInfo::CI_AllowsMemory)
&& !(info & TargetInfo::CI_AllowsRegister)) {
- if (InputExpr->isLvalue(Context) != Expr::LV_Valid)
+ if (CheckAsmLValue(InputExpr, *this))
return StmtError(Diag(InputExpr->getSubExpr()->getLocStart(),
diag::err_asm_invalid_lvalue_in_input)
<< InputConstraint << InputExpr->getSubExpr()->getSourceRange());
diff --git a/test/Sema/heinous-extensions-off.c b/test/Sema/heinous-extensions-off.c
new file mode 100644
index 0000000000..2b15f29bf4
--- /dev/null
+++ b/test/Sema/heinous-extensions-off.c
@@ -0,0 +1,10 @@
+// RUN: clang %s -verify
+
+int foo() {
+ int a;
+ // PR3788
+ asm("nop" : : "m"((int)(a))); // expected-error {{cast in a inline asm context requiring an l-value}}
+ // PR3794
+ asm("nop" : "=r"((unsigned)a)); // expected-error {{cast in a inline asm context requiring an l-value}}
+}
+
diff --git a/test/Sema/heinous-extensions-on.c b/test/Sema/heinous-extensions-on.c
new file mode 100644
index 0000000000..6b831f14d1
--- /dev/null
+++ b/test/Sema/heinous-extensions-on.c
@@ -0,0 +1,10 @@
+// RUN: clang %s -verify -fheinous-gnu-extensions
+
+int foo() {
+ int a;
+ // PR3788
+ asm("nop" : : "m"((int)(a))); // expected-warning {{cast in a inline asm context requiring an l-value}}
+ // PR3794
+ asm("nop" : "=r"((unsigned)a)); // expected-warning {{cast in a inline asm context requiring an l-value}}
+}
+