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