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
This commit is contained in:
David Majnemer 2014-12-29 09:30:33 +00:00
parent 4b4be84a2f
commit 0f4d641005
2 changed files with 52 additions and 14 deletions

View File

@ -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();
OutputConstraintInfos.push_back(Info);
// If this is dependent, just continue.
if (OutputExpr->isTypeDependent())
continue;
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());
}
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())
continue;
unsigned Size = Context.getTypeSize(Ty);
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.

View File

@ -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}}
}