From nobody Wed Sep 30 16:33:01 2026 X-Original-To: dev-commits-src-main@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 4hw0vy0BF3z6tnHv for ; Wed, 30 Sep 2026 16:33:02 +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 4hw0vx6c4fz4fP5 for ; Wed, 30 Sep 2026 16:33:01 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1790785981; 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=NtZWYUAVjEcP2FXJIoE25q49EXohgWfygFKPg5KMzcA=; b=XtO60A1dITdCT/1pK9vCOazuRGCB9fDcUUIzs8VILupzs23RgtCNSMRrJkTYs6yw71QwWz KIcFPIivHUMTV21W+TzQGNp8P2Q2/Bi087vs3n8c/z+v0PdRosOTHaK5WSUUMM6B7XoAnz EYgx9Gor6XU3f3iIjmOlntcJjI+iGT+IQtLNMynAvTAracrvNb8f+stY2XsHk4LUNHWvp5 Nt9HuZytYbSHFnFmRT+7DK8BlcmGnsRHlDNNprD3xnGcaM2JifhZ380Z8H59vTdjy4bHDc H6+yDyguLK4z2vDTpdqWo3nrT0ie6NxjFAj6gc9dNLoBYQyxnvh4rI+vi0UjPg== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1790785981; b=qqWHo7hC0XMXjUfmLl5TecmT9tJlCb3csqBvpbEiJFvkFopVOU3dD5MbvvEE7XNp/PM2PG UzL4eXLF4HrSfYH7JsDJIWRsr8OpSmkraFKPJfHN405C6eJwLNKOSCS8qGrvvvS+ch6dDB HDH0iAPeEDT32V8La1xdqXtpEIY+QWjiZ8nDVxQgwzZJBA87gxIe3Fuhqe1lIZ9h/BzWiP 60DIVR3HgJMpzPIR7hKQL/a2Qr7qZdumYUrWAeNChVYPerblxYLfjLybSmukVsnL5uNIZm XQbTj3pqjKWRJkIZHSAED6F9rABXqGsXoLswHy36e5JATRc7dK6iJU7qn4/55g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1790785981; 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=NtZWYUAVjEcP2FXJIoE25q49EXohgWfygFKPg5KMzcA=; b=PekNh8DcN5qRbK2hFsuQg8wgHYu3s5uCrqfwMvf0jvt+fLrXlmd6oKQvLodMwbQKpZTJFM PkwqahqucShJvlxCwdQUcnVf9PnwMmIfHuiECnNNK64EN18E2mLoRfILVGlBBzw/QxxnL2 fIKsidQfmcDXlqozB7djzYvUj2g+PYzuQDNtwnQDauN3R1VyiZ74Adf9Euki3BNucm8kwY 0IWuhCY2rL5e21MDpLjf1NR8fUdbGAFC/gUgXRGRa1BEuSXO1E3nhgXdPLW/XUVaCJWF0l L+ZTo3U5IvKiH6S139KvngpsGwE9J/JnlZjs57dAStSrgyvfO9cd74MkAVXAdQ== 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 4hw0vx5fV6ztRV for ; Wed, 30 Sep 2026 16:33:01 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 375d8 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 30 Sep 2026 16:33:01 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Dimitry Andric Subject: git: ca3747034ef4 - main - Merge commit c52392a6f464 from llvm-project (by ShengYi Hung): List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@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/main X-Git-Reftype: branch X-Git-Commit: ca3747034ef484b024a202d213a2e08b16066791 Auto-Submitted: auto-generated Date: Wed, 30 Sep 2026 16:33:01 +0000 Message-Id: <6abd39bd.375d8.7bcf05ef@gitrepo.freebsd.org> The branch main has been updated by dim: URL: https://cgit.FreeBSD.org/src/commit/?id=ca3747034ef484b024a202d213a2e08b16066791 commit ca3747034ef484b024a202d213a2e08b16066791 Author: Dimitry Andric AuthorDate: 2026-09-28 18:12:33 +0000 Commit: Dimitry Andric CommitDate: 2026-09-30 16:32: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 --- .../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();