summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaStmtAsm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaStmtAsm.cpp')
-rw-r--r--lib/Sema/SemaStmtAsm.cpp160
1 files changed, 101 insertions, 59 deletions
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index 0db15ea1f646a..9e084c99d0dd4 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -27,6 +27,58 @@
using namespace clang;
using namespace sema;
+/// Remove the upper-level LValueToRValue cast from an expression.
+static void removeLValueToRValueCast(Expr *E) {
+ Expr *Parent = E;
+ Expr *ExprUnderCast = nullptr;
+ SmallVector<Expr *, 8> ParentsToUpdate;
+
+ while (true) {
+ ParentsToUpdate.push_back(Parent);
+ if (auto *ParenE = dyn_cast<ParenExpr>(Parent)) {
+ Parent = ParenE->getSubExpr();
+ continue;
+ }
+
+ Expr *Child = nullptr;
+ CastExpr *ParentCast = dyn_cast<CastExpr>(Parent);
+ if (ParentCast)
+ Child = ParentCast->getSubExpr();
+ else
+ return;
+
+ if (auto *CastE = dyn_cast<CastExpr>(Child))
+ if (CastE->getCastKind() == CK_LValueToRValue) {
+ ExprUnderCast = CastE->getSubExpr();
+ // LValueToRValue cast inside GCCAsmStmt requires an explicit cast.
+ ParentCast->setSubExpr(ExprUnderCast);
+ break;
+ }
+ Parent = Child;
+ }
+
+ // Update parent expressions to have same ValueType as the underlying.
+ assert(ExprUnderCast &&
+ "Should be reachable only if LValueToRValue cast was found!");
+ auto ValueKind = ExprUnderCast->getValueKind();
+ for (Expr *E : ParentsToUpdate)
+ E->setValueKind(ValueKind);
+}
+
+/// Emit a warning about usage of "noop"-like casts for lvalues (GNU extension)
+/// and fix the argument with removing LValueToRValue cast from the expression.
+static void emitAndFixInvalidAsmCastLValue(const Expr *LVal, Expr *BadArgument,
+ Sema &S) {
+ if (!S.getLangOpts().HeinousExtensions) {
+ S.Diag(LVal->getBeginLoc(), diag::err_invalid_asm_cast_lvalue)
+ << BadArgument->getSourceRange();
+ } else {
+ S.Diag(LVal->getBeginLoc(), diag::warn_invalid_asm_cast_lvalue)
+ << BadArgument->getSourceRange();
+ }
+ removeLValueToRValueCast(BadArgument);
+}
+
/// 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
@@ -34,7 +86,7 @@ using namespace sema;
///
/// 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) {
+static bool CheckAsmLValue(Expr *E, Sema &S) {
// Type dependent expressions will be checked during instantiation.
if (E->isTypeDependent())
return false;
@@ -46,12 +98,7 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) {
// are supposed to allow.
const Expr *E2 = E->IgnoreParenNoopCasts(S.Context);
if (E != E2 && E2->isLValue()) {
- if (!S.getLangOpts().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();
+ emitAndFixInvalidAsmCastLValue(E2, E, S);
// Accept, even if we emitted an error diagnostic.
return false;
}
@@ -90,13 +137,13 @@ static bool CheckNakedParmReference(Expr *E, Sema &S) {
while (WorkList.size()) {
Expr *E = WorkList.pop_back_val();
if (isa<CXXThisExpr>(E)) {
- S.Diag(E->getLocStart(), diag::err_asm_naked_this_ref);
+ S.Diag(E->getBeginLoc(), diag::err_asm_naked_this_ref);
S.Diag(Func->getAttr<NakedAttr>()->getLocation(), diag::note_attribute);
return true;
}
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
if (isa<ParmVarDecl>(DRE->getDecl())) {
- S.Diag(DRE->getLocStart(), diag::err_asm_naked_parm_ref);
+ S.Diag(DRE->getBeginLoc(), diag::err_asm_naked_parm_ref);
S.Diag(Func->getAttr<NakedAttr>()->getLocation(), diag::note_attribute);
return true;
}
@@ -131,7 +178,7 @@ static bool checkExprMemoryConstraintCompat(Sema &S, Expr *E,
EType = ExprGlobalRegVar;
if (EType != ExprSafeType) {
- S.Diag(E->getLocStart(), diag::err_asm_non_addr_value_in_memory_constraint)
+ S.Diag(E->getBeginLoc(), diag::err_asm_non_addr_value_in_memory_constraint)
<< EType << is_input_expr << Info.getConstraintStr()
<< E->getSourceRange();
return true;
@@ -185,7 +232,7 @@ getClobberConflictLocation(MultiExprArg Exprs, StringLiteral **Constraints,
Clobber = Target.getNormalizedGCCRegisterName(Clobber, true);
// Go over the output's registers we collected
if (InOutVars.count(Clobber))
- return Clobbers[i]->getLocStart();
+ return Clobbers[i]->getBeginLoc();
}
return SourceLocation();
}
@@ -226,9 +273,9 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
if (!Context.getTargetInfo().validateOutputConstraint(Info))
- return StmtError(Diag(Literal->getLocStart(),
- diag::err_asm_invalid_output_constraint)
- << Info.getConstraintStr());
+ return StmtError(
+ Diag(Literal->getBeginLoc(), diag::err_asm_invalid_output_constraint)
+ << Info.getConstraintStr());
ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
if (ER.isInvalid())
@@ -264,24 +311,18 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
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();
- }
+ emitAndFixInvalidAsmCastLValue(LVal, OutputExpr, *this);
// Accept, even if we emitted an error diagnostic.
break;
}
case Expr::MLV_IncompleteType:
case Expr::MLV_IncompleteVoidType:
- if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(),
+ if (RequireCompleteType(OutputExpr->getBeginLoc(), Exprs[i]->getType(),
diag::err_dereference_incomplete_type))
return StmtError();
LLVM_FALLTHROUGH;
default:
- return StmtError(Diag(OutputExpr->getLocStart(),
+ return StmtError(Diag(OutputExpr->getBeginLoc(),
diag::err_asm_invalid_lvalue_in_output)
<< OutputExpr->getSourceRange());
}
@@ -289,9 +330,9 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
unsigned Size = Context.getTypeSize(OutputExpr->getType());
if (!Context.getTargetInfo().validateOutputSize(Literal->getString(),
Size))
- return StmtError(Diag(OutputExpr->getLocStart(),
- diag::err_asm_invalid_output_size)
- << Info.getConstraintStr());
+ return StmtError(
+ Diag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_output_size)
+ << Info.getConstraintStr());
}
SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
@@ -307,9 +348,9 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos,
Info)) {
- return StmtError(Diag(Literal->getLocStart(),
- diag::err_asm_invalid_input_constraint)
- << Info.getConstraintStr());
+ return StmtError(
+ Diag(Literal->getBeginLoc(), diag::err_asm_invalid_input_constraint)
+ << Info.getConstraintStr());
}
ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
@@ -331,22 +372,23 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// Only allow void types for memory constraints.
if (Info.allowsMemory() && !Info.allowsRegister()) {
if (CheckAsmLValue(InputExpr, *this))
- return StmtError(Diag(InputExpr->getLocStart(),
+ return StmtError(Diag(InputExpr->getBeginLoc(),
diag::err_asm_invalid_lvalue_in_input)
<< Info.getConstraintStr()
<< InputExpr->getSourceRange());
} else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) {
if (!InputExpr->isValueDependent()) {
- llvm::APSInt Result;
- if (!InputExpr->EvaluateAsInt(Result, Context))
- return StmtError(
- Diag(InputExpr->getLocStart(), diag::err_asm_immediate_expected)
- << Info.getConstraintStr() << InputExpr->getSourceRange());
- if (!Info.isValidAsmImmediate(Result))
- return StmtError(Diag(InputExpr->getLocStart(),
- diag::err_invalid_asm_value_for_constraint)
- << Result.toString(10) << Info.getConstraintStr()
- << InputExpr->getSourceRange());
+ Expr::EvalResult EVResult;
+ if (!InputExpr->EvaluateAsRValue(EVResult, Context, true))
+ return StmtError(
+ Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected)
+ << Info.getConstraintStr() << InputExpr->getSourceRange());
+ llvm::APSInt Result = EVResult.Val.getInt();
+ if (!Info.isValidAsmImmediate(Result))
+ return StmtError(Diag(InputExpr->getBeginLoc(),
+ diag::err_invalid_asm_value_for_constraint)
+ << Result.toString(10) << Info.getConstraintStr()
+ << InputExpr->getSourceRange());
}
} else {
@@ -359,10 +401,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
if (Info.allowsRegister()) {
if (InputExpr->getType()->isVoidType()) {
- return StmtError(Diag(InputExpr->getLocStart(),
- diag::err_asm_invalid_type_in_input)
- << InputExpr->getType() << Info.getConstraintStr()
- << InputExpr->getSourceRange());
+ return StmtError(
+ Diag(InputExpr->getBeginLoc(), diag::err_asm_invalid_type_in_input)
+ << InputExpr->getType() << Info.getConstraintStr()
+ << InputExpr->getSourceRange());
}
}
@@ -373,16 +415,16 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
continue;
if (!Ty->isVoidType() || !Info.allowsMemory())
- if (RequireCompleteType(InputExpr->getLocStart(), Exprs[i]->getType(),
+ if (RequireCompleteType(InputExpr->getBeginLoc(), Exprs[i]->getType(),
diag::err_dereference_incomplete_type))
return StmtError();
unsigned Size = Context.getTypeSize(Ty);
if (!Context.getTargetInfo().validateInputSize(Literal->getString(),
Size))
- return StmtError(Diag(InputExpr->getLocStart(),
- diag::err_asm_invalid_input_size)
- << Info.getConstraintStr());
+ return StmtError(
+ Diag(InputExpr->getBeginLoc(), diag::err_asm_invalid_input_size)
+ << Info.getConstraintStr());
}
// Check that the clobbers are valid.
@@ -393,8 +435,9 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
StringRef Clobber = Literal->getString();
if (!Context.getTargetInfo().isValidClobber(Clobber))
- return StmtError(Diag(Literal->getLocStart(),
- diag::err_asm_unknown_register_name) << Clobber);
+ return StmtError(
+ Diag(Literal->getBeginLoc(), diag::err_asm_unknown_register_name)
+ << Clobber);
}
GCCAsmStmt *NS =
@@ -446,7 +489,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
if (!Context.getTargetInfo().validateConstraintModifier(
Literal->getString(), Piece.getModifier(), Size,
SuggestedModifier)) {
- Diag(Exprs[ConstraintIdx]->getLocStart(),
+ Diag(Exprs[ConstraintIdx]->getBeginLoc(),
diag::warn_asm_mismatched_size_modifier);
if (!SuggestedModifier.empty()) {
@@ -469,7 +512,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
if (NumAlternatives == ~0U)
NumAlternatives = AltCount;
else if (NumAlternatives != AltCount)
- return StmtError(Diag(NS->getOutputExpr(i)->getLocStart(),
+ return StmtError(Diag(NS->getOutputExpr(i)->getBeginLoc(),
diag::err_asm_unexpected_constraint_alternatives)
<< NumAlternatives << AltCount);
}
@@ -482,7 +525,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
if (NumAlternatives == ~0U)
NumAlternatives = AltCount;
else if (NumAlternatives != AltCount)
- return StmtError(Diag(NS->getInputExpr(i)->getLocStart(),
+ return StmtError(Diag(NS->getInputExpr(i)->getBeginLoc(),
diag::err_asm_unexpected_constraint_alternatives)
<< NumAlternatives << AltCount);
@@ -499,10 +542,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// Make sure no more than one input constraint matches each output.
assert(TiedTo < InputMatchedToOutput.size() && "TiedTo value out of range");
if (InputMatchedToOutput[TiedTo] != ~0U) {
- Diag(NS->getInputExpr(i)->getLocStart(),
+ Diag(NS->getInputExpr(i)->getBeginLoc(),
diag::err_asm_input_duplicate_match)
<< TiedTo;
- Diag(NS->getInputExpr(InputMatchedToOutput[TiedTo])->getLocStart(),
+ Diag(NS->getInputExpr(InputMatchedToOutput[TiedTo])->getBeginLoc(),
diag::note_asm_input_duplicate_first)
<< TiedTo;
return StmtError();
@@ -590,10 +633,9 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
continue;
}
- Diag(InputExpr->getLocStart(),
- diag::err_asm_tying_incompatible_types)
- << InTy << OutTy << OutputExpr->getSourceRange()
- << InputExpr->getSourceRange();
+ Diag(InputExpr->getBeginLoc(), diag::err_asm_tying_incompatible_types)
+ << InTy << OutTy << OutputExpr->getSourceRange()
+ << InputExpr->getSourceRange();
return StmtError();
}