diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/CodeGen/CGStmt.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 39 |
2 files changed, 39 insertions, 7 deletions
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index fddc547fd34..91aa88569e3 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/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/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 96e59f0f82b..39f21f853a3 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/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()); |