diff options
Diffstat (limited to 'lib/Sema/SemaStmtAsm.cpp')
-rw-r--r-- | lib/Sema/SemaStmtAsm.cpp | 160 |
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(); } |