From 0f4d641005fae99ada19f9cfe83f2f798fe91705 Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Mon, 29 Dec 2014 09:30:33 +0000 Subject: [PATCH] Sema: Only permit permit modifiable l-values as asm output params Functions are l-values in C++ but shouldn't be available as output parameters in inline assembly. Neither should overloaded function l-values. This fixes PR21949. llvm-svn: 224916 --- clang/lib/Sema/SemaStmtAsm.cpp | 56 +++++++++++++++++++++++-------- clang/test/SemaCXX/statements.cpp | 10 ++++++ 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index b31bb250dd8d..24a91716cb85 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -132,31 +132,54 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, diag::err_asm_invalid_output_constraint) << Info.getConstraintStr()); + ExprResult ER = CheckPlaceholderExpr(Exprs[i]); + if (ER.isInvalid()) + return StmtError(); + Exprs[i] = ER.get(); + // Check that the output exprs are valid lvalues. Expr *OutputExpr = Exprs[i]; - if (CheckAsmLValue(OutputExpr, *this)) - return StmtError(Diag(OutputExpr->getLocStart(), - diag::err_asm_invalid_lvalue_in_output) - << OutputExpr->getSourceRange()); // Referring to parameters is not allowed in naked functions. if (CheckNakedParmReference(OutputExpr, *this)) return StmtError(); - if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(), - diag::err_dereference_incomplete_type)) - return StmtError(); - OutputConstraintInfos.push_back(Info); - const Type *Ty = OutputExpr->getType().getTypePtr(); - - // If this is a dependent type, just continue. We don't know the size of a - // dependent type. - if (Ty->isDependentType()) + // If this is dependent, just continue. + if (OutputExpr->isTypeDependent()) continue; - unsigned Size = Context.getTypeSize(Ty); + Expr::isModifiableLvalueResult IsLV = + OutputExpr->isModifiableLvalue(Context, /*Loc=*/nullptr); + switch (IsLV) { + case Expr::MLV_Valid: + // Cool, this is an lvalue. + break; + case Expr::MLV_LValueCast: { + const Expr *LVal = OutputExpr->IgnoreParenNoopCasts(Context); + if (!getLangOpts().HeinousExtensions) { + Diag(LVal->getLocStart(), diag::err_invalid_asm_cast_lvalue) + << OutputExpr->getSourceRange(); + } else { + Diag(LVal->getLocStart(), diag::warn_invalid_asm_cast_lvalue) + << OutputExpr->getSourceRange(); + } + // Accept, even if we emitted an error diagnostic. + break; + } + case Expr::MLV_IncompleteType: + case Expr::MLV_IncompleteVoidType: + if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(), + diag::err_dereference_incomplete_type)) + return StmtError(); + default: + return StmtError(Diag(OutputExpr->getLocStart(), + diag::err_asm_invalid_lvalue_in_output) + << OutputExpr->getSourceRange()); + } + + unsigned Size = Context.getTypeSize(OutputExpr->getType()); if (!Context.getTargetInfo().validateOutputSize(Literal->getString(), Size)) return StmtError(Diag(OutputExpr->getLocStart(), @@ -182,6 +205,11 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, << Info.getConstraintStr()); } + ExprResult ER = CheckPlaceholderExpr(Exprs[i]); + if (ER.isInvalid()) + return StmtError(); + Exprs[i] = ER.get(); + Expr *InputExpr = Exprs[i]; // Referring to parameters is not allowed in naked functions. diff --git a/clang/test/SemaCXX/statements.cpp b/clang/test/SemaCXX/statements.cpp index 953a4a89458a..22648f3a081c 100644 --- a/clang/test/SemaCXX/statements.cpp +++ b/clang/test/SemaCXX/statements.cpp @@ -20,3 +20,13 @@ namespace PR6536 { struct A {}; void a() { goto out; A x; out: return; } } + +void test3() { + __asm__ ("":"+r" (test3)); // expected-error{{invalid lvalue in asm output}} +} + +void test4(); // expected-note{{possible target for call}} +void test4(int) { // expected-note{{possible target for call}} + // expected-error@+1{{overloaded function could not be resolved}} + __asm__ ("":"+r" (test4)); // expected-error{{invalid lvalue in asm output}} +}