Author: Timm Bäder Date: 2024-07-03T14:07:28+02:00 New Revision: c1af97db1e3846db1188149afe86cee6585dfc9a
URL: https://github.com/llvm/llvm-project/commit/c1af97db1e3846db1188149afe86cee6585dfc9a DIFF: https://github.com/llvm/llvm-project/commit/c1af97db1e3846db1188149afe86cee6585dfc9a.diff LOG: [clang][Interp] Diagnose comparisons against one-past-end pointers Added: Modified: clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Pointer.cpp clang/lib/AST/Interp/Pointer.h clang/test/AST/Interp/literals.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 328db219ca628..5d8362b4fa881 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -922,6 +922,7 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { return true; } + // Reject comparisons to weak pointers. for (const auto &P : {LHS, RHS}) { if (P.isZero()) continue; @@ -934,6 +935,20 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { } if (!Pointer::hasSameBase(LHS, RHS)) { + if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() && + RHS.getOffset() == 0) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) + << LHS.toDiagnosticString(S.getCtx()); + return false; + } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() && + LHS.getOffset() == 0) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) + << RHS.toDiagnosticString(S.getCtx()); + return false; + } + S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered))); return true; } else { diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index 4070d0c54225d..d6603f91fb127 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -143,7 +143,7 @@ APValue Pointer::toAPValue() const { if (isDummy() || isUnknownSizeArray() || Desc->asExpr()) return APValue(Base, CharUnits::Zero(), Path, - /*IsOnePastEnd=*/false, /*IsNullPtr=*/false); + /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false); // TODO: compute the offset into the object. CharUnits Offset = CharUnits::Zero(); @@ -181,7 +181,8 @@ APValue Pointer::toAPValue() const { // Just invert the order of the elements. std::reverse(Path.begin(), Path.end()); - return APValue(Base, Offset, Path, /*IsOnePastEnd=*/false, /*IsNullPtr=*/false); + return APValue(Base, Offset, Path, /*IsOnePastEnd=*/isOnePastEnd(), + /*IsNullPtr=*/false); } void Pointer::print(llvm::raw_ostream &OS) const { @@ -348,7 +349,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx) const { // Invalid pointers. if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() || - (!Ptr.isUnknownSizeArray() && Ptr.isOnePastEnd())) + Ptr.isPastEnd()) return false; // Primitive values. diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 5faec75cc3ec5..4f277eb7d9e58 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -556,10 +556,18 @@ class Pointer { if (isUnknownSizeArray()) return false; - return isElementPastEnd() || + return isElementPastEnd() || isPastEnd() || (getSize() == getOffset() && !isZeroSizeArray()); } + /// Checks if the pointer points past the end of the object. + bool isPastEnd() const { + if (isIntegralPointer()) + return false; + + return !isZero() && Offset > PointeeStorage.BS.Pointee->getSize(); + } + /// Checks if the pointer is an out-of-bounds element pointer. bool isElementPastEnd() const { return Offset == PastEndMark; } diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index f70ca79e216da..630d9b53cca25 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -1266,3 +1266,13 @@ static_assert(ReturnInStmtExpr() == 1, ""); // both-error {{not an integral cons // both-note {{in call to}} #endif + +namespace ComparisonAgainstOnePastEnd { + int a, b; + static_assert(&a + 1 == &b, ""); // both-error {{not an integral constant expression}} \ + // both-note {{comparison against pointer '&a + 1' that points past the end of a complete object has unspecified value}} + static_assert(&a == &b + 1, ""); // both-error {{not an integral constant expression}} \ + // both-note {{comparison against pointer '&b + 1' that points past the end of a complete object has unspecified value}} + + static_assert(&a + 1 == &b + 1, ""); // both-error {{static assertion failed}} +}; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits