summaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaExpr.cpp')
-rw-r--r--clang/lib/Sema/SemaExpr.cpp106
1 files changed, 82 insertions, 24 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 4ffce2c12366..562c98c6babe 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3352,6 +3352,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
case Decl::VarTemplateSpecialization:
case Decl::VarTemplatePartialSpecialization:
case Decl::Decomposition:
+ case Decl::Binding:
case Decl::OMPCapturedExpr:
// In C, "extern void blah;" is valid and is an r-value.
if (!getLangOpts().CPlusPlus && !type.hasQualifiers() &&
@@ -3371,20 +3372,13 @@ ExprResult Sema::BuildDeclarationNameExpr(
// potentially-evaluated contexts? Since the variable isn't actually
// captured in an unevaluated context, it seems that the answer is no.
if (!isUnevaluatedContext()) {
- QualType CapturedType = getCapturedDeclRefType(cast<VarDecl>(VD), Loc);
+ QualType CapturedType = getCapturedDeclRefType(cast<ValueDecl>(VD), Loc);
if (!CapturedType.isNull())
type = CapturedType;
}
-
break;
}
- case Decl::Binding:
- // These are always lvalues.
- valueKind = VK_LValue;
- type = type.getNonReferenceType();
- break;
-
case Decl::Function: {
if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) {
if (!Context.BuiltinInfo.isDirectlyAddressable(BID)) {
@@ -5587,10 +5581,6 @@ static FieldDecl *FindFieldDeclInstantiationPattern(const ASTContext &Ctx,
ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
assert(Field->hasInClassInitializer());
- // If we might have already tried and failed to instantiate, don't try again.
- if (Field->isInvalidDecl())
- return ExprError();
-
CXXThisScopeRAII This(*this, Field->getParent(), Qualifiers());
auto *ParentRD = cast<CXXRecordDecl>(Field->getParent());
@@ -5948,7 +5938,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
SmallVector<Expr *, 8> AllArgs;
VariadicCallType CallType = getVariadicCallType(FDecl, Proto, Fn);
- Invalid = GatherArgumentsForCall(Call->getBeginLoc(), FDecl, Proto, 0, Args,
+ Invalid = GatherArgumentsForCall(Call->getExprLoc(), FDecl, Proto, 0, Args,
AllArgs, CallType);
if (Invalid)
return true;
@@ -11790,6 +11780,51 @@ static bool checkForArray(const Expr *E) {
return D->getType()->isArrayType() && !D->isWeak();
}
+/// Detect patterns ptr + size >= ptr and ptr + size < ptr, where ptr is a
+/// pointer and size is an unsigned integer. Return whether the result is
+/// always true/false.
+static std::optional<bool> isTautologicalBoundsCheck(Sema &S, const Expr *LHS,
+ const Expr *RHS,
+ BinaryOperatorKind Opc) {
+ if (!LHS->getType()->isPointerType() ||
+ S.getLangOpts().isSignedOverflowDefined())
+ return std::nullopt;
+
+ // Canonicalize to >= or < predicate.
+ switch (Opc) {
+ case BO_GE:
+ case BO_LT:
+ break;
+ case BO_GT:
+ std::swap(LHS, RHS);
+ Opc = BO_LT;
+ break;
+ case BO_LE:
+ std::swap(LHS, RHS);
+ Opc = BO_GE;
+ break;
+ default:
+ return std::nullopt;
+ }
+
+ auto *BO = dyn_cast<BinaryOperator>(LHS);
+ if (!BO || BO->getOpcode() != BO_Add)
+ return std::nullopt;
+
+ Expr *Other;
+ if (Expr::isSameComparisonOperand(BO->getLHS(), RHS))
+ Other = BO->getRHS();
+ else if (Expr::isSameComparisonOperand(BO->getRHS(), RHS))
+ Other = BO->getLHS();
+ else
+ return std::nullopt;
+
+ if (!Other->getType()->isUnsignedIntegerType())
+ return std::nullopt;
+
+ return Opc == BO_GE;
+}
+
/// Diagnose some forms of syntactically-obvious tautological comparison.
static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
Expr *LHS, Expr *RHS,
@@ -11843,7 +11878,9 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
RHSStripped->getType()->isArrayType()) {
auto IsDeprArrayComparionIgnored =
S.getDiagnostics().isIgnored(diag::warn_depr_array_comparison, Loc);
- auto DiagID = !S.getLangOpts().CPlusPlus20 || IsDeprArrayComparionIgnored
+ auto DiagID = S.getLangOpts().CPlusPlus26
+ ? diag::warn_array_comparison_cxx26
+ : !S.getLangOpts().CPlusPlus20 || IsDeprArrayComparionIgnored
? diag::warn_array_comparison
: diag::warn_depr_array_comparison;
S.Diag(Loc, DiagID) << LHS->getSourceRange() << RHS->getSourceRange()
@@ -11897,6 +11934,12 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
S.PDiag(diag::warn_comparison_always)
<< 1 /*array comparison*/
<< Result);
+ } else if (std::optional<bool> Res =
+ isTautologicalBoundsCheck(S, LHS, RHS, Opc)) {
+ S.DiagRuntimeBehavior(Loc, nullptr,
+ S.PDiag(diag::warn_comparison_always)
+ << 2 /*pointer comparison*/
+ << (*Res ? AlwaysTrue : AlwaysFalse));
}
}
@@ -13248,11 +13291,24 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) {
if (!DRE) return NCCK_None;
if (!DRE->refersToEnclosingVariableOrCapture()) return NCCK_None;
- // The declaration must be a variable which is not declared 'const'.
- VarDecl *var = dyn_cast<VarDecl>(DRE->getDecl());
- if (!var) return NCCK_None;
- if (var->getType().isConstQualified()) return NCCK_None;
- assert(var->hasLocalStorage() && "capture added 'const' to non-local?");
+ ValueDecl *Value = dyn_cast<ValueDecl>(DRE->getDecl());
+
+ // The declaration must be a value which is not declared 'const'.
+ if (!Value || Value->getType().isConstQualified())
+ return NCCK_None;
+
+ BindingDecl *Binding = dyn_cast<BindingDecl>(Value);
+ if (Binding) {
+ assert(S.getLangOpts().CPlusPlus && "BindingDecl outside of C++?");
+ assert(!isa<BlockDecl>(Binding->getDeclContext()));
+ return NCCK_Lambda;
+ }
+
+ VarDecl *Var = dyn_cast<VarDecl>(Value);
+ if (!Var)
+ return NCCK_None;
+
+ assert(Var->hasLocalStorage() && "capture added 'const' to non-local?");
// Decide whether the first capture was for a block or a lambda.
DeclContext *DC = S.CurContext, *Prev = nullptr;
@@ -13261,16 +13317,16 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) {
// For init-capture, it is possible that the variable belongs to the
// template pattern of the current context.
if (auto *FD = dyn_cast<FunctionDecl>(DC))
- if (var->isInitCapture() &&
- FD->getTemplateInstantiationPattern() == var->getDeclContext())
+ if (Var->isInitCapture() &&
+ FD->getTemplateInstantiationPattern() == Var->getDeclContext())
break;
- if (DC == var->getDeclContext())
+ if (DC == Var->getDeclContext())
break;
Prev = DC;
DC = DC->getParent();
}
// Unless we have an init-capture, we've gone one step too far.
- if (!var->isInitCapture())
+ if (!Var->isInitCapture())
DC = Prev;
return (isa<BlockDecl>(DC) ? NCCK_Block : NCCK_Lambda);
}
@@ -19198,6 +19254,8 @@ bool Sema::NeedToCaptureVariable(ValueDecl *Var, SourceLocation Loc) {
}
QualType Sema::getCapturedDeclRefType(ValueDecl *Var, SourceLocation Loc) {
+ assert(Var && "Null value cannot be captured");
+
QualType CaptureType;
QualType DeclRefType;
@@ -19295,7 +19353,7 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
if (VD->getType()->isReferenceType())
return true;
if (auto *RD = VD->getType()->getAsCXXRecordDecl())
- if (RD->hasMutableFields())
+ if (RD->hasDefinition() && RD->hasMutableFields())
return true;
if (!VD->isUsableInConstantExpressions(S.Context))
return true;