diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index bf48139f57c0f..c80be094856b0 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1564,34 +1564,38 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E) { assert(E); - if (S.getLangOpts().CPlusPlus26) - return true; - - const auto &Loc = S.Current->getSource(OpPC); - if (const auto *NewExpr = dyn_cast(E)) { const FunctionDecl *OperatorNew = NewExpr->getOperatorNew(); - if (!S.getLangOpts().CPlusPlus26 && NewExpr->getNumPlacementArgs() > 0) { + if (NewExpr->getNumPlacementArgs() > 0) { // This is allowed pre-C++26, but only an std function. - if (S.Current->isStdFunction()) + if (S.getLangOpts().CPlusPlus26 || S.Current->isStdFunction()) return true; - S.FFDiag(Loc, diag::note_constexpr_new_placement) + S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement) << /*C++26 feature*/ 1 << E->getSourceRange(); - } else if (NewExpr->getNumPlacementArgs() == 1 && - !OperatorNew->isReservedGlobalPlacementOperator()) { - S.FFDiag(Loc, diag::note_constexpr_new_placement) - << /*Unsupported*/ 0 << E->getSourceRange(); } else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) { - S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable) + 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->isReplaceableGlobalAllocationFunction()) { - S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable) + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_new_non_replaceable) << isa(OperatorDelete) << OperatorDelete; + return false; } } diff --git a/clang/test/AST/ByteCode/cxx26.cpp b/clang/test/AST/ByteCode/cxx26.cpp index 0b0e2b21e8201..cd6b533065010 100644 --- a/clang/test/AST/ByteCode/cxx26.cpp +++ b/clang/test/AST/ByteCode/cxx26.cpp @@ -1,10 +1,33 @@ // RUN: %clang_cc1 -std=c++26 -fsyntax-only -fcxx-exceptions -verify=ref,both %s // RUN: %clang_cc1 -std=c++26 -fsyntax-only -fcxx-exceptions -verify=expected,both %s -fexperimental-new-constant-interpreter -// both-no-diagnostics +namespace std { + using size_t = decltype(sizeof(0)); +} namespace VoidCast { constexpr void* p = nullptr; constexpr int* q = static_cast(p); static_assert(q == nullptr); } + +namespace ReplaceableAlloc { + struct F { + static void* operator new(std::size_t n) { + return nullptr; // both-warning {{should not return a null pointer}} + } + }; + + constexpr F *createF() { + return new F(); // both-note {{call to class-specific 'operator new'}} + } + + constexpr bool foo() { + F *f = createF(); // both-note {{in call to}} + + delete f; + return true; + } + static_assert(foo()); // both-error {{not an integral constant expression}} \ + // both-note {{in call to}} +}