From nobody Wed Oct 07 17:21:14 2026 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4j0KfL6ZY8z6wCQx for ; Wed, 07 Oct 2026 17:21:14 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4j0KfL5tlcz4fY5 for ; Wed, 07 Oct 2026 17:21:14 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1791393674; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=b/9WDaaZfiOr18i/f5L9USunStRdahMFV2v54D8aaV0=; b=QZaHodlgnRQZ1Wq/KB4ab6dh+zM4FgKnnw+FRfyMneVyugG0l6pZS7LKHwTT0Ov8YUomJA iBQbl1beK+OpH4WqP78OM2tT+U6Ppygs8u1IX71/GAfER1rYRF9pE1q5cbzmRLQyUy9v0+ 94Ur6H7mCYHpH1SdThKoQYSQzrWND7iHaWwUE2FPgApSdY5SA/fJZh2TMSI4x+FwYlpZLo bNtRIiQRsg3tQd8xGnRbPi5fKF7nz/iOj8Wa+wsAX+Jt96dzRdSLxUfV4SU/LPAybDn8JG 8S+GXrCZMZHaScBT01WnQEiKWnwUyMT4OXOHtg+7nsh3z36IVig4u5GlMRl1+g== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1791393674; b=c/ZxA4SLnKBheNKBmhn9JdiNqKaABX4gEwulQRVuHyiusqtNffyBt64Vu2/9I27ZG1UQoq LzYXIaCd9RRKYnmLFxDoA5vROcwApYD6G4JDvoIERJjfMBEt+E4Ov196lv9f1B1ffM25++ MzQV1wGeg/wSnaQ4kUFNrlauRv9jyuiyLMAkEpTbbLmPJqdMzblPF6UyMQ2WO+vDzUBL02 9dCQFXUL7xV7WHKqoSB0mneyB6oVTVYmO22pSyib0Ke5Ye54TMFVW0Iwi6AU3J1/JhJ/pR u5butry7oDsD9LWxz4mfYNTqCwQ8eK6LFeD8AyB9zc4+x4VkAxd5fbPADgO6Bw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1791393674; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=b/9WDaaZfiOr18i/f5L9USunStRdahMFV2v54D8aaV0=; b=Pt7rzfv0PPL6SqWaoBmxWMfuSEQxxou0EAydPTI5srfy/rXLGX6YR94s41LhwHx1WobTMY GOxrI3F9uTjDgDFJCDrhBiD/HzggzA5xdQHADj3r5D1zRR93cbnO4HgFwgHggHegIr/Exr KnzSIHfBbY4t9wkzfhk9aTLsYRCpmbwdRro+kP5n6kFIh5Q1/G3PSdiGEdeVB6+aaJkh1x zH86BAh6nmVsM4mPxrlgN28p5F5pewUAMD5cNhoc1rOgOhXmTr9VyqYvTNKJ3KICrKCSs9 YUC3u2XaFPt0DHfy7D2PAVW7n3K6WCrAFCM+cyZaqzG0hCzsWViqixH0GaZaIw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4j0KfL4xMrz1335 for ; Wed, 07 Oct 2026 17:21:14 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3a125 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 07 Oct 2026 17:21:14 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Dimitry Andric Subject: git: b259c7f6e9ec - stable/14 - Merge commit c52392a6f464 from llvm-project (by ShengYi Hung): List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: dim X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: b259c7f6e9ec4d0c95ca6b34c1a5db55b45089dc Auto-Submitted: auto-generated Date: Wed, 07 Oct 2026 17:21:14 +0000 Message-Id: <6ac67f8a.3a125.6416596b@gitrepo.freebsd.org> The branch stable/14 has been updated by dim: URL: https://cgit.FreeBSD.org/src/commit/?id=b259c7f6e9ec4d0c95ca6b34c1a5db55b45089dc commit b259c7f6e9ec4d0c95ca6b34c1a5db55b45089dc Author: Dimitry Andric AuthorDate: 2026-09-28 18:12:33 +0000 Commit: Dimitry Andric CommitDate: 2026-10-07 17:20:47 +0000 Merge commit c52392a6f464 from llvm-project (by ShengYi Hung): [Clang][ExprConst] Drop PRValue for nothrow new (#226753) A user defined operator new can accept prvalue for nothrow. However, it should not be a ConstExpr. Early returns by isUsableAsGlobalAllocationFunctionInConstantEvaluation instead of doing LValue evaluation. Also, move CheckPlacement new logic into new OpCode. This decouples checking from Interp.cpp to Compiler.cpp. This fixes "Assertion failed: (E->isGLValue() || E->getType()->isFunctionType() || E->getType()->isVoidType() || isa(E->IgnoreParens())), function EvaluateLValue" when building the databases/mariadb123-server port. MFC after: 1 week (cherry picked from commit ca3747034ef484b024a202d213a2e08b16066791) --- .../clang/lib/AST/ByteCode/Compiler.cpp | 20 ++++--- .../llvm-project/clang/lib/AST/ByteCode/Interp.cpp | 65 +++++++++++----------- .../llvm-project/clang/lib/AST/ByteCode/Interp.h | 1 + .../llvm-project/clang/lib/AST/ByteCode/Opcodes.td | 4 ++ .../llvm-project/clang/lib/AST/ExprConstant.cpp | 42 ++++++++------ 5 files changed, 71 insertions(+), 61 deletions(-) diff --git a/contrib/llvm-project/clang/lib/AST/ByteCode/Compiler.cpp b/contrib/llvm-project/clang/lib/AST/ByteCode/Compiler.cpp index afa3b7ea7de7..04c3d6458de0 100644 --- a/contrib/llvm-project/clang/lib/AST/ByteCode/Compiler.cpp +++ b/contrib/llvm-project/clang/lib/AST/ByteCode/Compiler.cpp @@ -3456,19 +3456,21 @@ bool Compiler::VisitCXXNewExpr(const CXXNewExpr *E) { // alignof(X) and X has new-extended alignment). if (PlacementArgs == 1) { const Expr *Arg1 = E->getPlacementArg(0); - if (Arg1->getType()->isNothrowT()) { + if (OperatorNew->isReservedGlobalPlacementOperator()) { + if (!this->emitCheckPlacementNew(E, E)) + return false; + PlacementDest = Arg1; + } else if ( + Arg1->getType()->isNothrowT() && + OperatorNew + ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) { if (!this->discard(Arg1)) return false; IsNoThrow = true; } else { - // Invalid unless we have C++26 or are in a std:: function. - if (!this->emitInvalidNewDeleteExpr(E, E)) - return false; - - // If we have a placement-new destination, we'll later use that instead - // of allocating. - if (OperatorNew->isReservedGlobalPlacementOperator()) - PlacementDest = Arg1; + // Any other placement list is invalid. This includes a user-declared + // allocation function taking std::nothrow_t, e.g. by value. + return this->emitInvalidNewDeleteExpr(E, E); } } else { // Always invalid. diff --git a/contrib/llvm-project/clang/lib/AST/ByteCode/Interp.cpp b/contrib/llvm-project/clang/lib/AST/ByteCode/Interp.cpp index 457de2bed37d..987e32911f81 100644 --- a/contrib/llvm-project/clang/lib/AST/ByteCode/Interp.cpp +++ b/contrib/llvm-project/clang/lib/AST/ByteCode/Interp.cpp @@ -1802,9 +1802,6 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, if (!S.inConstantContext() && isConstexprUnknown(Ptr)) return false; - if (!InvalidNewDeleteExpr(S, OpPC, E)) - return false; - const auto *NewExpr = cast(E); QualType StorageType = Ptr.getFieldDesc()->getDataType(S.getASTContext()); const ASTContext &ASTCtx = S.getASTContext(); @@ -1843,45 +1840,45 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E) { assert(E); + const SourceInfo &Loc = S.Current->getSource(OpPC); if (const auto *NewExpr = dyn_cast(E)) { const FunctionDecl *OperatorNew = NewExpr->getOperatorNew(); - if (NewExpr->getNumPlacementArgs() > 0) { - // This is allowed pre-C++26, but only an std function. - if (S.getLangOpts().CPlusPlus26 || S.Current->isStdFunction()) - return true; - S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement) - << /*C++26 feature*/ 1 << E->getSourceRange(); - } else if ( - !OperatorNew - ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) { - S.FFDiag(S.Current->getSource(OpPC), - diag::note_constexpr_new_non_replaceable) - << isa(OperatorNew) << OperatorNew; - return false; - } else if (!S.getLangOpts().CPlusPlus26 && - NewExpr->getNumPlacementArgs() == 1 && - !OperatorNew->isReservedGlobalPlacementOperator()) { - if (!S.getLangOpts().CPlusPlus26) { - S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement) - << /*Unsupported*/ 0 << E->getSourceRange(); - return false; - } - return true; - } - } else { - const auto *DeleteExpr = cast(E); - const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete(); - if (!OperatorDelete - ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) { - S.FFDiag(S.Current->getSource(OpPC), - diag::note_constexpr_new_non_replaceable) - << isa(OperatorDelete) << OperatorDelete; + // The only new-placement list we support is (std::nothrow), and only for + // the replaceable global allocation functions. + bool IsNothrowForm = NewExpr->getNumPlacementArgs() == 1 && + NewExpr->getPlacementArg(0)->getType()->isNothrowT(); + if (NewExpr->getNumPlacementArgs() > 0 && !IsNothrowForm) { + S.FFDiag(Loc, diag::note_constexpr_new_placement) + << /*Unsupported*/ 0 << E->getSourceRange(); return false; } + + assert( + !OperatorNew->isUsableAsGlobalAllocationFunctionInConstantEvaluation()); + S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable) + << isa(OperatorNew) << OperatorNew; + return false; } + const auto *DeleteExpr = cast(E); + const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete(); + assert(!OperatorDelete + ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()); + S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable) + << isa(OperatorDelete) << OperatorDelete; + return false; +} + +bool CheckPlacementNew(InterpState &S, CodePtr OpPC, const Expr *E) { + // Placement new is allowed in C++26. Before that, it is only allowed in a + // std:: function or if [[msvc::constexpr]] was used. + if (S.getLangOpts().CPlusPlus26 || S.Current->isStdFunction()) + return true; + + S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement) + << /*C++26 feature*/ 1 << E->getSourceRange(); return false; } diff --git a/contrib/llvm-project/clang/lib/AST/ByteCode/Interp.h b/contrib/llvm-project/clang/lib/AST/ByteCode/Interp.h index 9d17f96c97c8..17850c8510b1 100644 --- a/contrib/llvm-project/clang/lib/AST/ByteCode/Interp.h +++ b/contrib/llvm-project/clang/lib/AST/ByteCode/Interp.h @@ -3398,6 +3398,7 @@ bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) { return CheckNewTypeMismatch(S, OpPC, E, static_cast(Size)); } bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E); +bool CheckPlacementNew(InterpState &S, CodePtr OpPC, const Expr *E); template ::T> inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, diff --git a/contrib/llvm-project/clang/lib/AST/ByteCode/Opcodes.td b/contrib/llvm-project/clang/lib/AST/ByteCode/Opcodes.td index 57e01f7bd9da..7d41c2c63334 100644 --- a/contrib/llvm-project/clang/lib/AST/ByteCode/Opcodes.td +++ b/contrib/llvm-project/clang/lib/AST/ByteCode/Opcodes.td @@ -851,6 +851,10 @@ def InvalidNewDeleteExpr : Opcode { let Args = [ArgExpr]; } +def CheckPlacementNew : Opcode { + let Args = [ArgExpr]; +} + def CheckNewTypeMismatchArray : Opcode { let Types = [IntegerTypeClass]; let Args = [ArgExpr]; diff --git a/contrib/llvm-project/clang/lib/AST/ExprConstant.cpp b/contrib/llvm-project/clang/lib/AST/ExprConstant.cpp index bfecae972940..fa2c42ab509c 100644 --- a/contrib/llvm-project/clang/lib/AST/ExprConstant.cpp +++ b/contrib/llvm-project/clang/lib/AST/ExprConstant.cpp @@ -10322,23 +10322,21 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) { bool IsNothrow = false; bool IsPlacement = false; - if (E->getNumPlacementArgs() == 1 && - E->getPlacementArg(0)->getType()->isNothrowT()) { - // The only new-placement list we support is of the form (std::nothrow). - // - // FIXME: There is no restriction on this, but it's not clear that any - // other form makes any sense. We get here for cases such as: - // - // new (std::align_val_t{N}) X(int) - // - // (which should presumably be valid only if N is a multiple of - // alignof(int), and in any case can't be deallocated unless N is - // alignof(X) and X has new-extended alignment). - LValue Nothrow; - if (!EvaluateLValue(E->getPlacementArg(0), Nothrow, Info)) - return false; - IsNothrow = true; - } else if (OperatorNew->isReservedGlobalPlacementOperator()) { + // The only new-placement list we support (other than the reserved placement + // form) is of the form (std::nothrow). + // + // FIXME: There is no restriction on this, but it's not clear that any + // other form makes any sense. We get here for cases such as: + // + // new (std::align_val_t{N}) X(int) + // + // (which should presumably be valid only if N is a multiple of + // alignof(int), and in any case can't be deallocated unless N is + // alignof(X) and X has new-extended alignment). + bool HasNothrowArg = E->getNumPlacementArgs() == 1 && + E->getPlacementArg(0)->getType()->isNothrowT(); + + if (OperatorNew->isReservedGlobalPlacementOperator()) { if (Info.CurrentCall->isStdFunction() || Info.getLangOpts().CPlusPlus26 || (Info.CurrentCall->CanEvalMSConstexpr && OperatorNew->hasAttr())) { @@ -10353,15 +10351,23 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) { << /*C++26 feature*/ 1 << E->getSourceRange(); return false; } - } else if (E->getNumPlacementArgs()) { + } else if (E->getNumPlacementArgs() && !HasNothrowArg) { Info.FFDiag(E, diag::note_constexpr_new_placement) << /*Unsupported*/ 0 << E->getSourceRange(); return false; } else if (!OperatorNew ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) { + // [expr.const] only permits new-expressions that select a replaceable + // global allocation function. Check this before evaluating a + // (std::nothrow) placement argument. Info.FFDiag(E, diag::note_constexpr_new_non_replaceable) << isa(OperatorNew) << OperatorNew; return false; + } else if (HasNothrowArg) { + LValue Nothrow; + if (!EvaluateLValue(E->getPlacementArg(0), Nothrow, Info)) + return false; + IsNothrow = true; } const Expr *Init = E->getInitializer();