aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp217
1 files changed, 141 insertions, 76 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp b/contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp
index 73f3183c163f..b24a8ab110b2 100644
--- a/contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp
+++ b/contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp
@@ -385,6 +385,14 @@ void Sema::ActOnStartOfCompoundStmt(bool IsStmtExpr) {
PushCompoundScope(IsStmtExpr);
}
+void Sema::ActOnAfterCompoundStatementLeadingPragmas() {
+ if (getCurFPFeatures().isFPConstrained()) {
+ FunctionScopeInfo *FSI = getCurFunction();
+ assert(FSI);
+ FSI->setUsesFPIntrin();
+ }
+}
+
void Sema::ActOnFinishOfCompoundStmt() {
PopCompoundScope();
}
@@ -397,11 +405,6 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
ArrayRef<Stmt *> Elts, bool isStmtExpr) {
const unsigned NumElts = Elts.size();
- // Mark the current function as usng floating point constrained intrinsics
- if (getCurFPFeatures().isFPConstrained())
- if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext))
- F->setUsesFPIntrin(true);
-
// If we're in C89 mode, check that we don't have any decls after stmts. If
// so, emit an extension diagnostic.
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
@@ -467,7 +470,7 @@ Sema::ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val) {
ExprResult ER = E;
if (!E->isValueDependent())
- ER = VerifyIntegerConstantExpression(E);
+ ER = VerifyIntegerConstantExpression(E, AllowFold);
if (!ER.isInvalid())
ER = DefaultLvalueConversion(ER.get());
if (!ER.isInvalid())
@@ -574,11 +577,11 @@ public:
};
}
-StmtResult
-Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt,
- ConditionResult Cond,
- Stmt *thenStmt, SourceLocation ElseLoc,
- Stmt *elseStmt) {
+StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr,
+ SourceLocation LParenLoc, Stmt *InitStmt,
+ ConditionResult Cond, SourceLocation RParenLoc,
+ Stmt *thenStmt, SourceLocation ElseLoc,
+ Stmt *elseStmt) {
if (Cond.isInvalid())
Cond = ConditionResult(
*this, nullptr,
@@ -597,12 +600,40 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt,
DiagnoseEmptyStmtBody(CondExpr->getEndLoc(), thenStmt,
diag::warn_empty_if_body);
- return BuildIfStmt(IfLoc, IsConstexpr, InitStmt, Cond, thenStmt, ElseLoc,
- elseStmt);
+ if (IsConstexpr) {
+ auto DiagnoseLikelihood = [&](const Stmt *S) {
+ if (const Attr *A = Stmt::getLikelihoodAttr(S)) {
+ Diags.Report(A->getLocation(),
+ diag::warn_attribute_has_no_effect_on_if_constexpr)
+ << A << A->getRange();
+ Diags.Report(IfLoc,
+ diag::note_attribute_has_no_effect_on_if_constexpr_here)
+ << SourceRange(IfLoc, LParenLoc.getLocWithOffset(-1));
+ }
+ };
+ DiagnoseLikelihood(thenStmt);
+ DiagnoseLikelihood(elseStmt);
+ } else {
+ std::tuple<bool, const Attr *, const Attr *> LHC =
+ Stmt::determineLikelihoodConflict(thenStmt, elseStmt);
+ if (std::get<0>(LHC)) {
+ const Attr *ThenAttr = std::get<1>(LHC);
+ const Attr *ElseAttr = std::get<2>(LHC);
+ Diags.Report(ThenAttr->getLocation(),
+ diag::warn_attributes_likelihood_ifstmt_conflict)
+ << ThenAttr << ThenAttr->getRange();
+ Diags.Report(ElseAttr->getLocation(), diag::note_conflicting_attribute)
+ << ElseAttr << ElseAttr->getRange();
+ }
+ }
+
+ return BuildIfStmt(IfLoc, IsConstexpr, LParenLoc, InitStmt, Cond, RParenLoc,
+ thenStmt, ElseLoc, elseStmt);
}
StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
- Stmt *InitStmt, ConditionResult Cond,
+ SourceLocation LParenLoc, Stmt *InitStmt,
+ ConditionResult Cond, SourceLocation RParenLoc,
Stmt *thenStmt, SourceLocation ElseLoc,
Stmt *elseStmt) {
if (Cond.isInvalid())
@@ -612,7 +643,8 @@ StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
setFunctionHasBranchProtectedScope();
return IfStmt::Create(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first,
- Cond.get().second, thenStmt, ElseLoc, elseStmt);
+ Cond.get().second, LParenLoc, RParenLoc, thenStmt,
+ ElseLoc, elseStmt);
}
namespace {
@@ -640,8 +672,7 @@ static bool CmpCaseVals(const std::pair<llvm::APSInt, CaseStmt*>& lhs,
return true;
if (lhs.first == rhs.first &&
- lhs.second->getCaseLoc().getRawEncoding()
- < rhs.second->getCaseLoc().getRawEncoding())
+ lhs.second->getCaseLoc() < rhs.second->getCaseLoc())
return true;
return false;
}
@@ -739,7 +770,9 @@ ExprResult Sema::CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond) {
}
StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
- Stmt *InitStmt, ConditionResult Cond) {
+ SourceLocation LParenLoc,
+ Stmt *InitStmt, ConditionResult Cond,
+ SourceLocation RParenLoc) {
Expr *CondExpr = Cond.get().second;
assert((Cond.isInvalid() || CondExpr) && "switch with no condition");
@@ -761,7 +794,8 @@ StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
setFunctionHasBranchIntoScope();
- auto *SS = SwitchStmt::Create(Context, InitStmt, Cond.get().first, CondExpr);
+ auto *SS = SwitchStmt::Create(Context, InitStmt, Cond.get().first, CondExpr,
+ LParenLoc, RParenLoc);
getCurFunction()->SwitchStack.push_back(
FunctionScopeInfo::SwitchInfo(SS, false));
return SS;
@@ -1244,10 +1278,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// Produce a nice diagnostic if multiple values aren't handled.
if (!UnhandledNames.empty()) {
- DiagnosticBuilder DB = Diag(CondExpr->getExprLoc(),
- TheDefaultStmt ? diag::warn_def_missing_case
+ auto DB = Diag(CondExpr->getExprLoc(), TheDefaultStmt
+ ? diag::warn_def_missing_case
: diag::warn_missing_case)
- << (int)UnhandledNames.size();
+ << (int)UnhandledNames.size();
for (size_t I = 0, E = std::min(UnhandledNames.size(), (size_t)3);
I != E; ++I)
@@ -1787,15 +1821,27 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
// C99 6.8.5p3: The declaration part of a 'for' statement shall only
// declare identifiers for objects having storage class 'auto' or
// 'register'.
+ const Decl *NonVarSeen = nullptr;
+ bool VarDeclSeen = false;
for (auto *DI : DS->decls()) {
- VarDecl *VD = dyn_cast<VarDecl>(DI);
- if (VD && VD->isLocalVarDecl() && !VD->hasLocalStorage())
- VD = nullptr;
- if (!VD) {
- Diag(DI->getLocation(), diag::err_non_local_variable_decl_in_for);
- DI->setInvalidDecl();
+ if (VarDecl *VD = dyn_cast<VarDecl>(DI)) {
+ VarDeclSeen = true;
+ if (VD->isLocalVarDecl() && !VD->hasLocalStorage()) {
+ Diag(DI->getLocation(), diag::err_non_local_variable_decl_in_for);
+ DI->setInvalidDecl();
+ }
+ } else if (!NonVarSeen) {
+ // Keep track of the first non-variable declaration we saw so that
+ // we can diagnose if we don't see any variable declarations. This
+ // covers a case like declaring a typedef, function, or structure
+ // type rather than a variable.
+ NonVarSeen = DI;
}
}
+ // Diagnose if we saw a non-variable declaration but no variable
+ // declarations.
+ if (NonVarSeen && !VarDeclSeen)
+ Diag(NonVarSeen->getLocation(), diag::err_non_variable_decl_in_for);
}
}
@@ -3039,12 +3085,13 @@ bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
// variable will no longer be used.
if (VD->hasAttr<BlocksAttr>()) return false;
+ // ...non-volatile...
+ if (VD->getType().isVolatileQualified())
+ return false;
+
if (CESK & CES_AllowDifferentTypes)
return true;
- // ...non-volatile...
- if (VD->getType().isVolatileQualified()) return false;
-
// Variables with higher required alignment than their type's ABI
// alignment cannot use NRVO.
if (!VD->getType()->isDependentType() && VD->hasAttr<AlignedAttr>() &&
@@ -3070,15 +3117,18 @@ bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
/// If move-initialization is not possible, such that we must fall back to
/// treating the operand as an lvalue, we will leave Res in its original
/// invalid state.
-static void TryMoveInitialization(Sema& S,
- const InitializedEntity &Entity,
+///
+/// \returns Whether we need to do the second overload resolution. If the first
+/// overload resolution fails, or if the first overload resolution succeeds but
+/// the selected constructor/operator doesn't match the additional criteria, we
+/// need to do the second overload resolution.
+static bool TryMoveInitialization(Sema &S, const InitializedEntity &Entity,
const VarDecl *NRVOCandidate,
- QualType ResultType,
- Expr *&Value,
+ QualType ResultType, Expr *&Value,
bool ConvertingConstructorsOnly,
- ExprResult &Res) {
+ bool IsDiagnosticsCheck, ExprResult &Res) {
ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(),
- CK_NoOp, Value, VK_XValue);
+ CK_NoOp, Value, VK_XValue, FPOptionsOverride());
Expr *InitExpr = &AsRvalue;
@@ -3087,8 +3137,11 @@ static void TryMoveInitialization(Sema& S,
InitializationSequence Seq(S, Entity, Kind, InitExpr);
- if (!Seq)
- return;
+ bool NeedSecondOverloadResolution = true;
+ if (!Seq &&
+ (IsDiagnosticsCheck || Seq.getFailedOverloadResult() != OR_Deleted)) {
+ return NeedSecondOverloadResolution;
+ }
for (const InitializationSequence::Step &Step : Seq.steps()) {
if (Step.Kind != InitializationSequence::SK_ConstructorInitialization &&
@@ -3131,15 +3184,19 @@ static void TryMoveInitialization(Sema& S,
}
}
+ NeedSecondOverloadResolution = false;
// Promote "AsRvalue" to the heap, since we now need this
// expression node to persist.
- Value = ImplicitCastExpr::Create(S.Context, Value->getType(), CK_NoOp,
- Value, nullptr, VK_XValue);
+ Value =
+ ImplicitCastExpr::Create(S.Context, Value->getType(), CK_NoOp, Value,
+ nullptr, VK_XValue, FPOptionsOverride());
// Complete type-checking the initialization of the return type
// using the constructor we found.
Res = Seq.Perform(S, Entity, Kind, Value);
}
+
+ return NeedSecondOverloadResolution;
}
/// Perform the initialization of a potentially-movable value, which
@@ -3164,6 +3221,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
// select the constructor for the copy is first performed as if the object
// were designated by an rvalue.
ExprResult Res = ExprError();
+ bool NeedSecondOverloadResolution = true;
if (AllowNRVO) {
bool AffectedByCWG1579 = false;
@@ -3180,15 +3238,14 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
}
if (NRVOCandidate) {
- TryMoveInitialization(*this, Entity, NRVOCandidate, ResultType, Value,
- true, Res);
+ NeedSecondOverloadResolution = TryMoveInitialization(
+ *this, Entity, NRVOCandidate, ResultType, Value, true, false, Res);
}
- if (!Res.isInvalid() && AffectedByCWG1579) {
+ if (!NeedSecondOverloadResolution && AffectedByCWG1579) {
QualType QT = NRVOCandidate->getType();
- if (QT.getNonReferenceType()
- .getUnqualifiedType()
- .isTriviallyCopyableType(Context)) {
+ if (QT.getNonReferenceType().getUnqualifiedType().isTriviallyCopyableType(
+ Context)) {
// Adding 'std::move' around a trivially copyable variable is probably
// pointless. Don't suggest it.
} else {
@@ -3202,12 +3259,12 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
Str += NRVOCandidate->getDeclName().getAsString();
Str += ")";
Diag(Value->getExprLoc(), diag::warn_return_std_move_in_cxx11)
- << Value->getSourceRange()
- << NRVOCandidate->getDeclName() << ResultType << QT;
+ << Value->getSourceRange() << NRVOCandidate->getDeclName()
+ << ResultType << QT;
Diag(Value->getExprLoc(), diag::note_add_std_move_in_cxx11)
<< FixItHint::CreateReplacement(Value->getSourceRange(), Str);
}
- } else if (Res.isInvalid() &&
+ } else if (NeedSecondOverloadResolution &&
!getDiagnostics().isIgnored(diag::warn_return_std_move,
Value->getExprLoc())) {
const VarDecl *FakeNRVOCandidate =
@@ -3226,7 +3283,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
ExprResult FakeRes = ExprError();
Expr *FakeValue = Value;
TryMoveInitialization(*this, Entity, FakeNRVOCandidate, ResultType,
- FakeValue, false, FakeRes);
+ FakeValue, false, true, FakeRes);
if (!FakeRes.isInvalid()) {
bool IsThrow =
(Entity.getKind() == InitializedEntity::EK_Exception);
@@ -3248,7 +3305,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
// Either we didn't meet the criteria for treating an lvalue as an rvalue,
// above, or overload resolution failed. Either way, we need to try
// (again) now with the return value expression as written.
- if (Res.isInvalid())
+ if (NeedSecondOverloadResolution)
Res = PerformCopyInitialization(Entity, SourceLocation(), Value);
return Res;
@@ -3290,9 +3347,14 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
if (HasDeducedReturnType) {
+ FunctionDecl *FD = CurLambda->CallOperator;
+ // If we've already decided this lambda is invalid, e.g. because
+ // we saw a `return` whose expression had an error, don't keep
+ // trying to deduce its return type.
+ if (FD->isInvalidDecl())
+ return StmtError();
// In C++1y, the return type may involve 'auto'.
// FIXME: Blocks might have a return type of 'auto' explicitly specified.
- FunctionDecl *FD = CurLambda->CallOperator;
if (CurCap->ReturnType.isNull())
CurCap->ReturnType = FD->getReturnType();
@@ -3587,7 +3649,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
Scope *CurScope) {
// Correct typos, in case the containing function returns 'auto' and
// RetValExp should determine the deduced type.
- ExprResult RetVal = CorrectDelayedTyposInExpr(RetValExp);
+ ExprResult RetVal = CorrectDelayedTyposInExpr(
+ RetValExp, nullptr, /*RecoverUncorrectedTypos=*/true);
if (RetVal.isInvalid())
return StmtError();
StmtResult R = BuildReturnStmt(ReturnLoc, RetVal.get());
@@ -3625,12 +3688,11 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (FD->hasAttrs())
Attrs = &FD->getAttrs();
if (FD->isNoReturn())
- Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
- << FD->getDeclName();
+ Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) << FD;
if (FD->isMain() && RetValExp)
if (isa<CXXBoolLiteralExpr>(RetValExp))
Diag(ReturnLoc, diag::warn_main_returns_bool_literal)
- << RetValExp->getSourceRange();
+ << RetValExp->getSourceRange();
if (FD->hasAttr<CmseNSEntryAttr>() && RetValExp) {
if (const auto *RT = dyn_cast<RecordType>(FnRetType.getCanonicalType())) {
if (RT->getDecl()->isOrContainsUnion())
@@ -3673,6 +3735,11 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (getLangOpts().CPlusPlus14) {
if (AutoType *AT = FnRetType->getContainedAutoType()) {
FunctionDecl *FD = cast<FunctionDecl>(CurContext);
+ // If we've already decided this function is invalid, e.g. because
+ // we saw a `return` whose expression had an error, don't keep
+ // trying to deduce its return type.
+ if (FD->isInvalidDecl())
+ return StmtError();
if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
FD->setInvalidDecl();
return StmtError();
@@ -3701,8 +3768,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
FunctionKind = 3;
Diag(ReturnLoc, diag::err_return_init_list)
- << CurDecl->getDeclName() << FunctionKind
- << RetValExp->getSourceRange();
+ << CurDecl << FunctionKind << RetValExp->getSourceRange();
// Drop the expression.
RetValExp = nullptr;
@@ -3729,9 +3795,8 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// return of void in constructor/destructor is illegal in C++.
if (D == diag::err_ctor_dtor_returns_void) {
NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
- Diag(ReturnLoc, D)
- << CurDecl->getDeclName() << isa<CXXDestructorDecl>(CurDecl)
- << RetValExp->getSourceRange();
+ Diag(ReturnLoc, D) << CurDecl << isa<CXXDestructorDecl>(CurDecl)
+ << RetValExp->getSourceRange();
}
// return (some void expression); is legal in C++.
else if (D != diag::ext_return_has_void_expr ||
@@ -3747,8 +3812,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
FunctionKind = 3;
Diag(ReturnLoc, D)
- << CurDecl->getDeclName() << FunctionKind
- << RetValExp->getSourceRange();
+ << CurDecl << FunctionKind << RetValExp->getSourceRange();
}
}
@@ -3766,25 +3830,26 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
} else if (!RetValExp && !HasDependentReturnType) {
FunctionDecl *FD = getCurFunctionDecl();
- unsigned DiagID;
if (getLangOpts().CPlusPlus11 && FD && FD->isConstexpr()) {
// C++11 [stmt.return]p2
- DiagID = diag::err_constexpr_return_missing_expr;
+ Diag(ReturnLoc, diag::err_constexpr_return_missing_expr)
+ << FD << FD->isConsteval();
FD->setInvalidDecl();
- } else if (getLangOpts().C99) {
- // C99 6.8.6.4p1 (ext_ since GCC warns)
- DiagID = diag::ext_return_missing_expr;
} else {
+ // C99 6.8.6.4p1 (ext_ since GCC warns)
// C90 6.6.6.4p4
- DiagID = diag::warn_return_missing_expr;
+ unsigned DiagID = getLangOpts().C99 ? diag::ext_return_missing_expr
+ : diag::warn_return_missing_expr;
+ // Note that at this point one of getCurFunctionDecl() or
+ // getCurMethodDecl() must be non-null (see above).
+ assert((getCurFunctionDecl() || getCurMethodDecl()) &&
+ "Not in a FunctionDecl or ObjCMethodDecl?");
+ bool IsMethod = FD == nullptr;
+ const NamedDecl *ND =
+ IsMethod ? cast<NamedDecl>(getCurMethodDecl()) : cast<NamedDecl>(FD);
+ Diag(ReturnLoc, DiagID) << ND << IsMethod;
}
- if (FD)
- Diag(ReturnLoc, DiagID)
- << FD->getIdentifier() << 0 /*fn*/ << FD->isConsteval();
- else
- Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
-
Result = ReturnStmt::Create(Context, ReturnLoc, /* RetExpr=*/nullptr,
/* NRVOCandidate=*/nullptr);
} else {