[flang-commits] [compiler-rt] [flang] [clang] [clang-tools-extra] [llvm] [clang] Add `::_placement_new` expression for built-in global placement new (PR #72209)
via flang-commits
flang-commits at lists.llvm.org
Sat Nov 18 13:33:08 PST 2023
https://github.com/MaxEW707 updated https://github.com/llvm/llvm-project/pull/72209
>From 75cf305fe732d00be910a6aa0afe79953c5b7186 Mon Sep 17 00:00:00 2001
From: MaxEW707 <82551778+MaxEW707 at users.noreply.github.com>
Date: Sun, 12 Nov 2023 11:36:58 -0500
Subject: [PATCH 1/4] Implement `::_placement_new` expression for built-in
global placement new without header includes, overload resolution or dealing
with std libraries that declare the global placement new with attributes that
cannot be redeclared.
---
clang/include/clang/AST/ExprCXX.h | 23 +++++++++
clang/include/clang/AST/Stmt.h | 4 ++
.../clang/Basic/DiagnosticParseKinds.td | 2 +
clang/include/clang/Basic/TokenKinds.def | 1 +
clang/include/clang/Sema/Sema.h | 4 +-
clang/lib/AST/ASTImporter.cpp | 18 ++++---
clang/lib/AST/ExprCXX.cpp | 34 +++++++++++++
clang/lib/AST/ExprConstant.cpp | 7 ++-
clang/lib/AST/JSONNodeDumper.cpp | 1 +
clang/lib/AST/StmtPrinter.cpp | 5 +-
clang/lib/AST/StmtProfile.cpp | 1 +
clang/lib/AST/TextNodeDumper.cpp | 2 +
clang/lib/CodeGen/CGExprCXX.cpp | 8 ++--
clang/lib/CodeGen/CodeGenModule.cpp | 5 +-
clang/lib/Interpreter/Interpreter.cpp | 4 +-
clang/lib/Parse/ParseDecl.cpp | 6 ++-
clang/lib/Parse/ParseExpr.cpp | 2 +-
clang/lib/Parse/ParseExprCXX.cpp | 19 ++++++--
clang/lib/Parse/ParseObjc.cpp | 1 +
clang/lib/Parse/ParseTentative.cpp | 3 +-
clang/lib/Sema/SemaExprCXX.cpp | 48 ++++++++++++++-----
clang/lib/Sema/TreeTransform.h | 6 +--
clang/lib/Serialization/ASTReaderStmt.cpp | 2 +
clang/lib/Serialization/ASTWriterStmt.cpp | 2 +
.../Checkers/CheckPlacementNew.cpp | 2 +-
.../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 9 ++--
clang/test/AST/ast-dump-expr.cpp | 14 ++++++
clang/test/CodeGenCXX/new.cpp | 44 ++++++++++++++++-
clang/test/SemaCXX/new-delete.cpp | 7 +++
29 files changed, 234 insertions(+), 50 deletions(-)
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 24278016431837b..d760af796aea28f 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -2282,6 +2282,13 @@ class CXXNewExpr final
QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
SourceRange DirectInitRange);
+ /// Build a c++ builtin placement new expression
+ CXXNewExpr(Expr *PlacementArg,
+ SourceRange TypeIdParens, std::optional<Expr *> ArraySize,
+ CXXNewInitializationStyle InitializationStyle, Expr *Initializer,
+ QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
+ SourceRange DirectInitRange);
+
/// Build an empty c++ new expression.
CXXNewExpr(EmptyShell Empty, bool IsArray, unsigned NumPlacementArgs,
bool IsParenTypeId);
@@ -2297,6 +2304,14 @@ class CXXNewExpr final
QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
SourceRange DirectInitRange);
+ /// Create a c++ builtin placement new expression.
+ static CXXNewExpr *
+ CreatePlacementNew(const ASTContext &Ctx, Expr *PlacementArg,
+ SourceRange TypeIdParens, std::optional<Expr *> ArraySize,
+ CXXNewInitializationStyle InitializationStyle, Expr *Initializer,
+ QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
+ SourceRange DirectInitRange);
+
/// Create an empty c++ new expression.
static CXXNewExpr *CreateEmpty(const ASTContext &Ctx, bool IsArray,
bool HasInit, unsigned NumPlacementArgs,
@@ -2332,6 +2347,12 @@ class CXXNewExpr final
FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
void setOperatorDelete(FunctionDecl *D) { OperatorDelete = D; }
+ bool isReservedPlacementNew() const {
+ if (CXXNewExprBits.IsPlacementNewExpr)
+ return true;
+ return OperatorNew->isReservedGlobalPlacementOperator();
+ }
+
bool isArray() const { return CXXNewExprBits.IsArray; }
/// This might return std::nullopt even if isArray() returns true,
@@ -2387,6 +2408,8 @@ class CXXNewExpr final
bool isGlobalNew() const { return CXXNewExprBits.IsGlobalNew; }
+ bool isPlacementNewExpr() const { return CXXNewExprBits.IsPlacementNewExpr; }
+
/// Whether this new-expression has any initializer at all.
bool hasInitializer() const {
switch (getInitializationStyle()) {
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index da7b37ce0e1211f..2dc3746aee4fd71 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -878,6 +878,10 @@ class alignas(void *) Stmt {
LLVM_PREFERRED_TYPE(bool)
unsigned IsParenTypeId : 1;
+ /// True is this if the builtin placement-new expression.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned IsPlacementNewExpr : 1;
+
/// The number of placement new arguments.
unsigned NumPlacementArgs;
};
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index de180344fcc5c74..c0ca7529fda892d 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -255,6 +255,8 @@ def err_expected_lbrace_in_compound_literal : Error<
"expected '{' in compound literal">;
def err_expected_while : Error<"expected 'while' in do/while loop">;
+def err_placement_new_expected_one_argument : Error<"expected only one argument in placement params">;
+
def err_expected_semi_after_stmt : Error<"expected ';' after %0 statement">;
def err_expected_semi_after_expr : Error<"expected ';' after expression">;
def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">;
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 3ce317d318f9bb6..a2dfc1a9e08691a 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -365,6 +365,7 @@ KEYWORD(typeid , KEYCXX)
KEYWORD(using , KEYCXX)
KEYWORD(virtual , KEYCXX)
KEYWORD(wchar_t , WCHARSUPPORT)
+KEYWORD(_placement_new , KEYCXX)
// C++ 2.5p2: Alternative Representations.
CXX_KEYWORD_OPERATOR(and , ampamp)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f69f366c1750918..ab9a0d0713435b6 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6810,14 +6810,14 @@ class Sema final {
bool ListInitialization);
/// ActOnCXXNew - Parsed a C++ 'new' expression.
- ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
+ ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, bool IsPlacementNewExpr,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
SourceRange TypeIdParens, Declarator &D,
Expr *Initializer);
ExprResult
- BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation PlacementLParen,
+ BuildCXXNew(SourceRange Range, bool UseGlobal, bool IsPlacementNewExpr, SourceLocation PlacementLParen,
MultiExprArg PlacementArgs, SourceLocation PlacementRParen,
SourceRange TypeIdParens, QualType AllocType,
TypeSourceInfo *AllocTypeInfo, std::optional<Expr *> ArraySize,
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index c4e931e220f69b5..3204fb69b3440f7 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -8102,12 +8102,18 @@ ExpectedStmt ASTNodeImporter::VisitCXXNewExpr(CXXNewExpr *E) {
ImportContainerChecked(E->placement_arguments(), ToPlacementArgs))
return std::move(Err);
- return CXXNewExpr::Create(
- Importer.getToContext(), E->isGlobalNew(), ToOperatorNew,
- ToOperatorDelete, E->passAlignment(), E->doesUsualArrayDeleteWantSize(),
- ToPlacementArgs, ToTypeIdParens, ToArraySize, E->getInitializationStyle(),
- ToInitializer, ToType, ToAllocatedTypeSourceInfo, ToSourceRange,
- ToDirectInitRange);
+ if (E->isPlacementNewExpr())
+ return CXXNewExpr::CreatePlacementNew(
+ Importer.getToContext(), ToPlacementArgs[0], ToTypeIdParens, ToArraySize,
+ E->getInitializationStyle(), ToInitializer, ToType, ToAllocatedTypeSourceInfo,
+ ToSourceRange, ToDirectInitRange);
+ else
+ return CXXNewExpr::Create(
+ Importer.getToContext(), E->isGlobalNew(), ToOperatorNew,
+ ToOperatorDelete, E->passAlignment(), E->doesUsualArrayDeleteWantSize(),
+ ToPlacementArgs, ToTypeIdParens, ToArraySize, E->getInitializationStyle(),
+ ToInitializer, ToType, ToAllocatedTypeSourceInfo, ToSourceRange,
+ ToDirectInitRange);
}
ExpectedStmt ASTNodeImporter::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 83af7998f683382..7c7f4c2f31542b9 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -207,6 +207,7 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
bool IsParenTypeId = TypeIdParens.isValid();
CXXNewExprBits.IsParenTypeId = IsParenTypeId;
CXXNewExprBits.NumPlacementArgs = PlacementArgs.size();
+ CXXNewExprBits.IsPlacementNewExpr = false;
if (ArraySize)
getTrailingObjects<Stmt *>()[arraySizeOffset()] = *ArraySize;
@@ -234,6 +235,18 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
setDependence(computeDependence(this));
}
+CXXNewExpr::CXXNewExpr(Expr *PlacementArg,
+ SourceRange TypeIdParens, std::optional<Expr *> ArraySize,
+ CXXNewInitializationStyle InitializationStyle, Expr *Initializer,
+ QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
+ SourceRange DirectInitRange)
+ : CXXNewExpr(true, nullptr, nullptr, false, false,
+ ArrayRef<Expr *>(&PlacementArg, 1), TypeIdParens, ArraySize,
+ InitializationStyle, Initializer, Ty,
+ AllocatedTypeInfo, Range, DirectInitRange) {
+ CXXNewExprBits.IsPlacementNewExpr = true;
+}
+
CXXNewExpr::CXXNewExpr(EmptyShell Empty, bool IsArray,
unsigned NumPlacementArgs, bool IsParenTypeId)
: Expr(CXXNewExprClass, Empty) {
@@ -265,6 +278,25 @@ CXXNewExpr *CXXNewExpr::Create(
AllocatedTypeInfo, Range, DirectInitRange);
}
+CXXNewExpr *CXXNewExpr::CreatePlacementNew(
+ const ASTContext &Ctx, Expr *PlacementArg,
+ SourceRange TypeIdParens, std::optional<Expr *> ArraySize,
+ CXXNewInitializationStyle InitializationStyle, Expr *Initializer,
+ QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
+ SourceRange DirectInitRange) {
+ bool IsArray = ArraySize.has_value();
+ bool HasInit = Initializer != nullptr;
+ bool IsParenTypeId = TypeIdParens.isValid();
+ void *Mem =
+ Ctx.Allocate(totalSizeToAlloc<Stmt *, SourceRange>(
+ IsArray + HasInit + 1, IsParenTypeId),
+ alignof(CXXNewExpr));
+ return new (Mem)
+ CXXNewExpr(PlacementArg, TypeIdParens,
+ ArraySize, InitializationStyle, Initializer, Ty,
+ AllocatedTypeInfo, Range, DirectInitRange);
+}
+
CXXNewExpr *CXXNewExpr::CreateEmpty(const ASTContext &Ctx, bool IsArray,
bool HasInit, unsigned NumPlacementArgs,
bool IsParenTypeId) {
@@ -277,6 +309,8 @@ CXXNewExpr *CXXNewExpr::CreateEmpty(const ASTContext &Ctx, bool IsArray,
}
bool CXXNewExpr::shouldNullCheckAllocation() const {
+ if (isPlacementNewExpr())
+ return false;
if (getOperatorNew()->getLangOpts().CheckNew)
return true;
return !getOperatorNew()->hasAttr<ReturnsNonNullAttr>() &&
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index e16fec6109e744e..7652e22a6a51b4f 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -9740,7 +9740,7 @@ static bool EvaluateArrayNewConstructExpr(EvalInfo &Info, LValue &This,
QualType AllocType);
bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
- if (!Info.getLangOpts().CPlusPlus20)
+ if (!Info.getLangOpts().CPlusPlus20 && !E->isPlacementNewExpr())
Info.CCEDiag(E, diag::note_constexpr_new);
// We cannot speculatively evaluate a delete expression.
@@ -9751,8 +9751,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
bool IsNothrow = false;
bool IsPlacement = false;
- if (OperatorNew->isReservedGlobalPlacementOperator() &&
- Info.CurrentCall->isStdFunction() && !E->isArray()) {
+ if (E->isReservedPlacementNew() && Info.CurrentCall->isStdFunction() && !E->isArray()) {
// FIXME Support array placement new.
assert(E->getNumPlacementArgs() == 1);
if (!EvaluatePointer(E->getPlacementArg(0), Result, Info))
@@ -9760,7 +9759,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
if (Result.Designator.Invalid)
return false;
IsPlacement = true;
- } else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
+ } else if (E->isPlacementNewExpr() || !OperatorNew->isReplaceableGlobalAllocationFunction()) {
Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
<< isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
return false;
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index ace5178bf625828..82c4f5e64416e21 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -1350,6 +1350,7 @@ void JSONNodeDumper::VisitCXXNewExpr(const CXXNewExpr *NE) {
attributeOnlyIfTrue("isGlobal", NE->isGlobalNew());
attributeOnlyIfTrue("isArray", NE->isArray());
attributeOnlyIfTrue("isPlacement", NE->getNumPlacementArgs() != 0);
+ attributeOnlyIfTrue("isPlacementNewExpr", NE->isPlacementNewExpr());
switch (NE->getInitializationStyle()) {
case CXXNewInitializationStyle::None:
case CXXNewInitializationStyle::Implicit:
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index ab4a013de5f552c..ce3d9b64de76ab0 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -2271,7 +2271,10 @@ void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) {
void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
if (E->isGlobalNew())
OS << "::";
- OS << "new ";
+ if (E->isPlacementNewExpr())
+ OS << "_placement_new ";
+ else
+ OS << "new ";
unsigned NumPlace = E->getNumPlacementArgs();
if (NumPlace > 0 && !isa<CXXDefaultArgExpr>(E->getPlacementArg(0))) {
OS << "(";
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 8128219dd6f63c9..c3590f50eebfd2e 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2096,6 +2096,7 @@ void StmtProfiler::VisitCXXNewExpr(const CXXNewExpr *S) {
ID.AddInteger(S->getNumPlacementArgs());
ID.AddBoolean(S->isGlobalNew());
ID.AddBoolean(S->isParenTypeId());
+ ID.AddBoolean(S->isPlacementNewExpr());
ID.AddInteger(llvm::to_underlying(S->getInitializationStyle()));
}
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index e8274fcd5cfe9cb..57b6b9087826355 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1356,6 +1356,8 @@ void TextNodeDumper::VisitCXXNewExpr(const CXXNewExpr *Node) {
OS << " global";
if (Node->isArray())
OS << " array";
+ if (Node->isPlacementNewExpr())
+ OS << " builtin placement-new expression";
if (Node->getOperatorNew()) {
OS << ' ';
dumpBareDeclRef(Node->getOperatorNew());
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 98ae56e2df88184..cfc16f2ffd3ad04 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -693,7 +693,7 @@ static CharUnits CalculateCookiePadding(CodeGenFunction &CGF,
// No cookie is required if the operator new[] being used is the
// reserved placement operator new[].
- if (E->getOperatorNew()->isReservedGlobalPlacementOperator())
+ if (E->isReservedPlacementNew())
return CharUnits::Zero();
return CGF.CGM.getCXXABI().GetArrayCookieSize(E);
@@ -1584,7 +1584,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// operator, just "inline" it directly.
Address allocation = Address::invalid();
CallArgList allocatorArgs;
- if (allocator->isReservedGlobalPlacementOperator()) {
+ if (E->isReservedPlacementNew()) {
assert(E->getNumPlacementArgs() == 1);
const Expr *arg = *E->placement_arguments().begin();
@@ -1599,6 +1599,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// Set up allocatorArgs for the call to operator delete if it's not
// the reserved global operator.
+ assert(!E->isPlacementNewExpr() || !E->getOperatorDelete());
if (E->getOperatorDelete() &&
!E->getOperatorDelete()->isReservedGlobalPlacementOperator()) {
allocatorArgs.add(RValue::get(allocSize), getContext().getSizeType());
@@ -1724,8 +1725,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// vptrs information which may be included in previous type.
// To not break LTO with different optimizations levels, we do it regardless
// of optimization level.
- if (CGM.getCodeGenOpts().StrictVTablePointers &&
- allocator->isReservedGlobalPlacementOperator())
+ if (CGM.getCodeGenOpts().StrictVTablePointers && E->isReservedPlacementNew())
result = Builder.CreateLaunderInvariantGroup(result);
// Emit sanitizer checks for pointer value now, so that in the case of an
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 4c7f516e308ca00..d0ed0289bcce52a 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -3837,7 +3837,10 @@ namespace {
}
bool VisitCXXNewExpr(CXXNewExpr *E) {
- SafeToInline = E->getOperatorNew()->hasAttr<DLLImportAttr>();
+ if (E->isPlacementNewExpr())
+ SafeToInline = true;
+ else
+ SafeToInline = E->getOperatorNew()->hasAttr<DLLImportAttr>();
return SafeToInline;
}
};
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 7968c62cbd3e7b3..93ba4a060342a22 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -606,8 +606,8 @@ class RuntimeInterfaceBuilder
Expr *Args[] = {AllocCall.get()};
ExprResult CXXNewCall = S.BuildCXXNew(
E->getSourceRange(),
- /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args,
- /*PlacementRParen=*/SourceLocation(),
+ /*UseGlobal=*/true, /*IsPlacementNewExpr=*/false,
+ /*PlacementLParen=*/SourceLocation(), Args, /*PlacementRParen=*/SourceLocation(),
/*TypeIdParens=*/SourceRange(), TSI->getType(), TSI, std::nullopt,
E->getSourceRange(), E);
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 78c3ab72979a007..18b2fd86e566e5c 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -5457,7 +5457,8 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::coloncolon: // ::foo::bar
if (NextToken().is(tok::kw_new) || // ::new
- NextToken().is(tok::kw_delete)) // ::delete
+ NextToken().is(tok::kw_delete) || // ::delete
+ NextToken().is(tok::kw__placement_new)) // ::_placement_new
return false;
if (TryAnnotateTypeOrScopeToken())
@@ -5650,7 +5651,8 @@ bool Parser::isDeclarationSpecifier(
if (!getLangOpts().CPlusPlus)
return false;
if (NextToken().is(tok::kw_new) || // ::new
- NextToken().is(tok::kw_delete)) // ::delete
+ NextToken().is(tok::kw_delete) || // ::delete
+ NextToken().is(tok::kw__placement_new)) // ::_placement_new
return false;
// Annotate typenames and C++ scope specifiers. If we get one, just
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 53fba3b2f59242b..9b2e03221d5d407 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1682,7 +1682,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
// ::new -> [C++] new-expression
// ::delete -> [C++] delete-expression
SourceLocation CCLoc = ConsumeToken();
- if (Tok.is(tok::kw_new)) {
+ if (Tok.is(tok::kw_new) || Tok.is(tok::kw__placement_new)) {
if (NotPrimaryExpression)
*NotPrimaryExpression = true;
Res = ParseCXXNewExpression(true, CCLoc);
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 99b4931004546c1..f21680834cfc531 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -186,7 +186,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
if (Tok.is(tok::coloncolon)) {
// ::new and ::delete aren't nested-name-specifiers.
tok::TokenKind NextKind = NextToken().getKind();
- if (NextKind == tok::kw_new || NextKind == tok::kw_delete)
+ if (NextKind == tok::kw_new || NextKind == tok::kw_delete || NextKind == tok::kw__placement_new)
return false;
if (NextKind == tok::l_brace) {
@@ -3171,7 +3171,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
///
ExprResult
Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
- assert(Tok.is(tok::kw_new) && "expected 'new' token");
+ assert((Tok.is(tok::kw_new) || Tok.is(tok::kw__placement_new)) && "expected 'new' token");
+ const bool IsPlacementNewExpr = Tok.is(tok::kw__placement_new);
ConsumeToken(); // Consume 'new'
// A '(' now can be a new-placement or the '(' wrapping the type-id in the
@@ -3201,6 +3202,14 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
return ExprError();
}
+ if (IsPlacementNewExpr) {
+ if (PlacementArgs.size() != 1) {
+ Diag(PlacementLParen, diag::err_placement_new_expected_one_argument);
+ SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
+ return ExprError();
+ }
+ }
+
if (PlacementArgs.empty()) {
// Reset the placement locations. There was no placement.
TypeIdParens = T.getRange();
@@ -3227,6 +3236,10 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
}
}
}
+ } else if (IsPlacementNewExpr) {
+ Diag(Tok, diag::err_expected_lparen_after) << "::_placement_new";
+ SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
+ return ExprError();
} else {
// A new-type-id is a simplified type-id, where essentially the
// direct-declarator is replaced by a direct-new-declarator.
@@ -3295,7 +3308,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
if (Initializer.isInvalid())
return Initializer;
- return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
+ return Actions.ActOnCXXNew(Start, UseGlobal, IsPlacementNewExpr, PlacementLParen,
PlacementArgs, PlacementRParen,
TypeIdParens, DeclaratorInfo, Initializer.get());
}
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index c0261c462b8834e..10764caf645dbea 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -1120,6 +1120,7 @@ IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
case tok::kw_mutable:
case tok::kw_namespace:
case tok::kw_new:
+ case tok::kw__placement_new:
case tok::kw_operator:
case tok::kw_private:
case tok::kw_protected:
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 28decc4fc43f9b8..623e3eb4ed70316 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -1445,7 +1445,8 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
case tok::coloncolon: { // ::foo::bar
const Token &Next = NextToken();
if (Next.isOneOf(tok::kw_new, // ::new
- tok::kw_delete)) // ::delete
+ tok::kw_delete, // ::delete
+ tok::kw__placement_new)) // ::_placement_new
return TPResult::False;
[[fallthrough]];
}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 023411c7edc946b..b8e606b3a45b965 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1875,7 +1875,7 @@ static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc,
/// \param Initializer The initializing expression or initializer-list, or null
/// if there is none.
ExprResult
-Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
+Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, bool IsPlacementNewExpr,
SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
SourceLocation PlacementRParen, SourceRange TypeIdParens,
Declarator &D, Expr *Initializer) {
@@ -1940,7 +1940,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer))
DirectInitRange = List->getSourceRange();
- return BuildCXXNew(SourceRange(StartLoc, D.getEndLoc()), UseGlobal,
+ return BuildCXXNew(SourceRange(StartLoc, D.getEndLoc()), UseGlobal, IsPlacementNewExpr,
PlacementLParen, PlacementArgs, PlacementRParen,
TypeIdParens, AllocType, TInfo, ArraySize, DirectInitRange,
Initializer);
@@ -1997,7 +1997,7 @@ void Sema::diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD,
}
}
-ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
+ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, bool IsPlacementNewExpr,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
@@ -2286,9 +2286,10 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
bool PassAlignment = getLangOpts().AlignedAllocation &&
Alignment > NewAlignment;
+ bool HaveDependentPlacementTypes = AllocType->isDependentType() || Expr::hasAnyTypeDependentArguments(PlacementArgs);
+
AllocationFunctionScope Scope = UseGlobal ? AFS_Global : AFS_Both;
- if (!AllocType->isDependentType() &&
- !Expr::hasAnyTypeDependentArguments(PlacementArgs) &&
+ if (!HaveDependentPlacementTypes && !IsPlacementNewExpr &&
FindAllocationFunctions(
StartLoc, SourceRange(PlacementLParen, PlacementRParen), Scope, Scope,
AllocType, ArraySize.has_value(), PassAlignment, PlacementArgs,
@@ -2298,15 +2299,29 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// If this is an array allocation, compute whether the usual array
// deallocation function for the type has a size_t parameter.
bool UsualArrayDeleteWantsSize = false;
- if (ArraySize && !AllocType->isDependentType())
+ if (!IsPlacementNewExpr && ArraySize && !AllocType->isDependentType())
UsualArrayDeleteWantsSize =
doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType);
- SmallVector<Expr *, 8> AllPlaceArgs;
- if (OperatorNew) {
+ if (IsPlacementNewExpr && !HaveDependentPlacementTypes) {
+ assert(PlacementArgs.size() == 1);
+ assert(UseGlobal);
+ QualType VoidPtr = Context.getPointerType(Context.VoidTy);
+
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, VoidPtr, false);
+ ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), PlacementArgs[0], false, false);
+ if (ArgE.isInvalid())
+ return ExprError();
+
+ Expr *Arg = ArgE.getAs<Expr>();
+ CheckArrayAccess(Arg);
+
+ PlacementArgs[0] = Arg;
+ } else if (OperatorNew) {
auto *Proto = OperatorNew->getType()->castAs<FunctionProtoType>();
VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction
: VariadicDoesNotApply;
+ SmallVector<Expr *, 8> AllPlaceArgs;
// We've already converted the placement args, just fill in any default
// arguments. Skip the first parameter because we don't have a corresponding
@@ -2471,21 +2486,28 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// Mark the new and delete operators as referenced.
if (OperatorNew) {
+ assert(!IsPlacementNewExpr);
if (DiagnoseUseOfDecl(OperatorNew, StartLoc))
return ExprError();
MarkFunctionReferenced(StartLoc, OperatorNew);
}
if (OperatorDelete) {
+ assert(!IsPlacementNewExpr);
if (DiagnoseUseOfDecl(OperatorDelete, StartLoc))
return ExprError();
MarkFunctionReferenced(StartLoc, OperatorDelete);
}
- return CXXNewExpr::Create(Context, UseGlobal, OperatorNew, OperatorDelete,
- PassAlignment, UsualArrayDeleteWantsSize,
- PlacementArgs, TypeIdParens, ArraySize, InitStyle,
- Initializer, ResultType, AllocTypeInfo, Range,
- DirectInitRange);
+ if (IsPlacementNewExpr)
+ return CXXNewExpr::CreatePlacementNew(Context, PlacementArgs[0], TypeIdParens, ArraySize,
+ InitStyle, Initializer, ResultType, AllocTypeInfo,
+ Range, DirectInitRange);
+ else
+ return CXXNewExpr::Create(Context, UseGlobal, OperatorNew, OperatorDelete,
+ PassAlignment, UsualArrayDeleteWantsSize,
+ PlacementArgs, TypeIdParens, ArraySize, InitStyle,
+ Initializer, ResultType, AllocTypeInfo, Range,
+ DirectInitRange);
}
/// Checks that a type is suitable as the allocated type
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index e24f710fdedd4e2..5fc64fa50dd431b 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3343,7 +3343,7 @@ class TreeTransform {
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildCXXNewExpr(SourceLocation StartLoc, bool UseGlobal,
+ ExprResult RebuildCXXNewExpr(SourceLocation StartLoc, bool UseGlobal, bool IsPlacementNewExpr,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
@@ -3351,7 +3351,7 @@ class TreeTransform {
TypeSourceInfo *AllocatedTypeInfo,
std::optional<Expr *> ArraySize,
SourceRange DirectInitRange, Expr *Initializer) {
- return getSema().BuildCXXNew(StartLoc, UseGlobal,
+ return getSema().BuildCXXNew(StartLoc, UseGlobal, IsPlacementNewExpr,
PlacementLParen,
PlacementArgs,
PlacementRParen,
@@ -12539,7 +12539,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
}
return getDerived().RebuildCXXNewExpr(
- E->getBeginLoc(), E->isGlobalNew(),
+ E->getBeginLoc(), E->isGlobalNew(), E->isPlacementNewExpr(),
/*FIXME:*/ E->getBeginLoc(), PlacementArgs,
/*FIXME:*/ E->getBeginLoc(), E->getTypeIdParens(), AllocType,
AllocTypeInfo, ArraySize, E->getDirectInitRange(), NewInit.get());
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index d7d0c0e5bb21b47..7f55e308fa1bb08 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1874,6 +1874,8 @@ void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
E->CXXNewExprBits.UsualArrayDeleteWantsSize = Record.readInt();
E->CXXNewExprBits.StoredInitializationStyle = Record.readInt();
+ E->CXXNewExprBits.IsPlacementNewExpr = Record.readInt();
+
assert((IsArray == E->isArray()) && "Wrong IsArray!");
assert((HasInit == E->hasInitializer()) && "Wrong HasInit!");
assert((NumPlacementArgs == E->getNumPlacementArgs()) &&
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 59be6828fafabf6..2fb5f40e6f448ac 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1799,6 +1799,8 @@ void ASTStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) {
Record.push_back(E->doesUsualArrayDeleteWantSize());
Record.push_back(E->CXXNewExprBits.StoredInitializationStyle);
+ Record.push_back(E->isPlacementNewExpr());
+
Record.AddDeclRef(E->getOperatorNew());
Record.AddDeclRef(E->getOperatorDelete());
Record.AddTypeSourceInfo(E->getAllocatedTypeSourceInfo());
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp
index 99e11a15c08dc2c..e1bdcae0377e7ef 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp
@@ -295,7 +295,7 @@ bool PlacementNewChecker::checkPlaceIsAlignedProperly(const CXXNewExpr *NE,
void PlacementNewChecker::checkPreStmt(const CXXNewExpr *NE,
CheckerContext &C) const {
// Check only the default placement new.
- if (!NE->getOperatorNew()->isReservedGlobalPlacementOperator())
+ if (!NE->isReservedPlacementNew())
return;
if (NE->getNumPlacementArgs() == 0)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 504fd7f05e0f99b..339b26d44cc8ad0 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1004,8 +1004,9 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
SVal symVal = UnknownVal();
FunctionDecl *FD = CNE->getOperatorNew();
- bool IsStandardGlobalOpNewFunction =
- FD->isReplaceableGlobalAllocationFunction();
+ bool IsStandardGlobalOpNewFunction = false;
+ if (FD)
+ IsStandardGlobalOpNewFunction = FD->isReplaceableGlobalAllocationFunction();
ProgramStateRef State = Pred->getState();
@@ -1046,7 +1047,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// where new can return NULL. If we end up supporting that option, we can
// consider adding a check for it here.
// C++11 [basic.stc.dynamic.allocation]p3.
- if (const auto *ProtoType = FD->getType()->getAs<FunctionProtoType>())
+ if (const auto *ProtoType = FD ? FD->getType()->getAs<FunctionProtoType>() : nullptr)
if (!ProtoType->isNothrow())
if (auto dSymVal = symVal.getAs<DefinedOrUnknownSVal>())
State = State->assume(*dSymVal, true);
@@ -1099,7 +1100,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// CXXNewExpr, we need to make sure that the constructed object is not
// immediately invalidated here. (The placement call should happen before
// the constructor call anyway.)
- if (FD->isReservedGlobalPlacementOperator()) {
+ if (CNE->isReservedPlacementNew()) {
// Non-array placement new should always return the placement location.
SVal PlacementLoc = State->getSVal(CNE->getPlacementArg(0), LCtx);
Result = svalBuilder.evalCast(PlacementLoc, CNE->getType(),
diff --git a/clang/test/AST/ast-dump-expr.cpp b/clang/test/AST/ast-dump-expr.cpp
index 69e65e22d61d0d0..7fddd913786cc1e 100644
--- a/clang/test/AST/ast-dump-expr.cpp
+++ b/clang/test/AST/ast-dump-expr.cpp
@@ -155,6 +155,12 @@ void UnaryExpressions(int *p) {
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:8> 'int *' lvalue ParmVar 0x{{[^ ]*}} 'p' 'int *'
+ ::_placement_new (p) int;
+ // CHECK: CXXNewExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:24> 'int *' global builtin placement-new expression
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void *' <BitCast>
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <LValueToRValue>
+ // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:21> 'int *' lvalue ParmVar 0x{{[^ ]*}} 'p' 'int *'
+
new (p) int{12};
// CHECK: CXXNewExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:17> 'int *' Function 0x{{[^ ]*}} 'operator new' 'void *(std::size_t, void *)'
// CHECK-NEXT: InitListExpr 0x{{[^ ]*}} <col:14, col:17> 'int'
@@ -163,6 +169,14 @@ void UnaryExpressions(int *p) {
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:8> 'int *' lvalue ParmVar 0x{{[^ ]*}} 'p' 'int *'
+ ::_placement_new (p) int{12};
+ // CHECK: CXXNewExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:30> 'int *' global builtin placement-new expression
+ // CHECK-NEXT: InitListExpr 0x{{[^ ]*}} <col:27, col:30> 'int'
+ // CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <col:28> 'int' 12
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void *' <BitCast>
+ // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <LValueToRValue>
+ // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:21> 'int *' lvalue ParmVar 0x{{[^ ]*}} 'p' 'int *'
+
::delete p;
// CHECK: CXXDeleteExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:12> 'void' global Function 0x{{[^ ]*}} 'operator delete' 'void (void *) noexcept'
// CHECK-NEXT: ImplicitCastExpr
diff --git a/clang/test/CodeGenCXX/new.cpp b/clang/test/CodeGenCXX/new.cpp
index e278d9acfe9ee23..7cd3232a295e0a1 100644
--- a/clang/test/CodeGenCXX/new.cpp
+++ b/clang/test/CodeGenCXX/new.cpp
@@ -219,6 +219,15 @@ namespace test15 {
new (p, true) A();
}
+ // CHECK-LABEL: define{{.*}} void @_ZN6test156test0cEPv(
+ // CHECK: [[P:%.*]] = load ptr, ptr
+ // CHECK-NOT: icmp eq ptr [[P]], null
+ // CHECK-NOT: br i1
+ // CHECK-NEXT: call void @_ZN6test151AC1Ev(ptr {{[^,]*}} [[P]])
+ void test0c(void *p) {
+ ::_placement_new (p) A();
+ }
+
// CHECK-LABEL: define{{.*}} void @_ZN6test156test1aEPv(
// CHECK: [[P:%.*]] = load ptr, ptr
// CHECK-NOT: icmp eq ptr [[P]], null
@@ -251,9 +260,24 @@ namespace test15 {
new (p, true) A[5];
}
+ // CHECK-LABEL: define{{.*}} void @_ZN6test156test1cEPv(
+ // CHECK: [[P:%.*]] = load ptr, ptr
+ // CHECK-NOT: icmp eq ptr [[P]], null
+ // CHECK-NOT: br i1
+ // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A:.*]], ptr [[P]], i64 5
+ // CHECK-NEXT: br label
+ // CHECK: [[CUR:%.*]] = phi ptr [ [[P]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
+ // CHECK-NEXT: call void @_ZN6test151AC1Ev(ptr {{[^,]*}} [[CUR]])
+ // CHECK-NEXT: [[NEXT]] = getelementptr inbounds [[A]], ptr [[CUR]], i64 1
+ // CHECK-NEXT: [[DONE:%.*]] = icmp eq ptr [[NEXT]], [[END]]
+ // CHECK-NEXT: br i1 [[DONE]]
+ void test1c(void *p) {
+ ::_placement_new (p) A[5];
+ }
+
// TODO: it's okay if all these size calculations get dropped.
// FIXME: maybe we should try to throw on overflow?
- // CHECK-LABEL: define{{.*}} void @_ZN6test155test2EPvi(
+ // CHECK-LABEL: define{{.*}} void @_ZN6test156test2aEPvi(
// CHECK: [[N:%.*]] = load i32, ptr
// CHECK-NEXT: [[T0:%.*]] = sext i32 [[N]] to i64
// CHECK-NEXT: [[P:%.*]] = load ptr, ptr
@@ -263,9 +287,25 @@ namespace test15 {
// CHECK-NEXT: br label
// CHECK: [[CUR:%.*]] = phi ptr [ [[P]],
// CHECK-NEXT: call void @_ZN6test151AC1Ev(ptr {{[^,]*}} [[CUR]])
- void test2(void *p, int n) {
+ void test2a(void *p, int n) {
new (p) A[n];
}
+
+ // TODO: it's okay if all these size calculations get dropped.
+ // FIXME: maybe we should try to throw on overflow?
+ // CHECK-LABEL: define{{.*}} void @_ZN6test156test2bEPvi(
+ // CHECK: [[N:%.*]] = load i32, ptr
+ // CHECK-NEXT: [[T0:%.*]] = sext i32 [[N]] to i64
+ // CHECK-NEXT: [[P:%.*]] = load ptr, ptr
+ // CHECK-NEXT: [[ISEMPTY:%.*]] = icmp eq i64 [[T0]], 0
+ // CHECK-NEXT: br i1 [[ISEMPTY]],
+ // CHECK: [[END:%.*]] = getelementptr inbounds [[A]], ptr [[P]], i64 [[T0]]
+ // CHECK-NEXT: br label
+ // CHECK: [[CUR:%.*]] = phi ptr [ [[P]],
+ // CHECK-NEXT: call void @_ZN6test151AC1Ev(ptr {{[^,]*}} [[CUR]])
+ void test2b(void *p, int n) {
+ ::_placement_new (p) A[n];
+ }
}
namespace PR10197 {
diff --git a/clang/test/SemaCXX/new-delete.cpp b/clang/test/SemaCXX/new-delete.cpp
index 0270e42b7389fec..20871c6ebc9bdf0 100644
--- a/clang/test/SemaCXX/new-delete.cpp
+++ b/clang/test/SemaCXX/new-delete.cpp
@@ -58,6 +58,9 @@ void good_news()
U *pu = new (ps) U;
V *pv = new (ps) V;
+ U *pu2 = ::_placement_new ((S*)0) U;
+ int *pi2 = ::_placement_new ((void*)0) int;
+
pi = new (S(1.0f, 2)) int;
(void)new int[true];
@@ -87,6 +90,10 @@ void bad_news(int *ip)
(void)new; // expected-error {{expected a type}}
(void)new 4; // expected-error {{expected a type}}
(void)new () int; // expected-error {{expected expression}}
+ (void)::_placement_new () int; // expected-error {{expected expression}}
+ (void)_placement_new (ip) int; // expected-error {{expected expression}}
+ (void)::_placement_new int; // expected-error {{expected '(' after '::_placement_new'}}
+ (void)::_placement_new (ip, ip) int; // expected-error {{expected only one argument in placement params}}
(void)new int[1.1];
#if __cplusplus <= 199711L
// expected-error at -2 {{array size expression must have integral or enumeration type, not 'double'}}
>From 2d2e463e10f27f9be21d6cad998e15923ca5f676 Mon Sep 17 00:00:00 2001
From: MaxEW707 <82551778+MaxEW707 at users.noreply.github.com>
Date: Tue, 14 Nov 2023 19:15:25 -0500
Subject: [PATCH 2/4] fix formatting errors
---
clang/include/clang/AST/ExprCXX.h | 9 ++--
clang/include/clang/Sema/Sema.h | 22 ++++-----
clang/lib/AST/ASTImporter.cpp | 12 ++---
clang/lib/AST/ExprCXX.cpp | 31 ++++++------
clang/lib/AST/ExprConstant.cpp | 6 ++-
clang/lib/Interpreter/Interpreter.cpp | 13 ++---
clang/lib/Parse/ParseDecl.cpp | 8 +--
clang/lib/Parse/ParseExprCXX.cpp | 10 ++--
clang/lib/Parse/ParseTentative.cpp | 4 +-
clang/lib/Sema/SemaExprCXX.cpp | 49 ++++++++++---------
clang/lib/Sema/TreeTransform.h | 17 +++----
.../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 3 +-
12 files changed, 94 insertions(+), 90 deletions(-)
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index d760af796aea28f..b769ddb69c613b5 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -2283,8 +2283,8 @@ class CXXNewExpr final
SourceRange DirectInitRange);
/// Build a c++ builtin placement new expression
- CXXNewExpr(Expr *PlacementArg,
- SourceRange TypeIdParens, std::optional<Expr *> ArraySize,
+ CXXNewExpr(Expr *PlacementArg, SourceRange TypeIdParens,
+ std::optional<Expr *> ArraySize,
CXXNewInitializationStyle InitializationStyle, Expr *Initializer,
QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
SourceRange DirectInitRange);
@@ -2308,8 +2308,9 @@ class CXXNewExpr final
static CXXNewExpr *
CreatePlacementNew(const ASTContext &Ctx, Expr *PlacementArg,
SourceRange TypeIdParens, std::optional<Expr *> ArraySize,
- CXXNewInitializationStyle InitializationStyle, Expr *Initializer,
- QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
+ CXXNewInitializationStyle InitializationStyle,
+ Expr *Initializer, QualType Ty,
+ TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
SourceRange DirectInitRange);
/// Create an empty c++ new expression.
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index ab9a0d0713435b6..ec1d86f7ead5694 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6810,18 +6810,18 @@ class Sema final {
bool ListInitialization);
/// ActOnCXXNew - Parsed a C++ 'new' expression.
- ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, bool IsPlacementNewExpr,
- SourceLocation PlacementLParen,
- MultiExprArg PlacementArgs,
- SourceLocation PlacementRParen,
- SourceRange TypeIdParens, Declarator &D,
- Expr *Initializer);
ExprResult
- BuildCXXNew(SourceRange Range, bool UseGlobal, bool IsPlacementNewExpr, SourceLocation PlacementLParen,
- MultiExprArg PlacementArgs, SourceLocation PlacementRParen,
- SourceRange TypeIdParens, QualType AllocType,
- TypeSourceInfo *AllocTypeInfo, std::optional<Expr *> ArraySize,
- SourceRange DirectInitRange, Expr *Initializer);
+ ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, bool IsPlacementNewExpr,
+ SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen, SourceRange TypeIdParens,
+ Declarator &D, Expr *Initializer);
+ ExprResult
+ BuildCXXNew(SourceRange Range, bool UseGlobal, bool IsPlacementNewExpr,
+ SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen, SourceRange TypeIdParens,
+ QualType AllocType, TypeSourceInfo *AllocTypeInfo,
+ std::optional<Expr *> ArraySize, SourceRange DirectInitRange,
+ Expr *Initializer);
/// Determine whether \p FD is an aligned allocation or deallocation
/// function that is unavailable.
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 3204fb69b3440f7..625d86b84ef0b26 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -8104,16 +8104,16 @@ ExpectedStmt ASTNodeImporter::VisitCXXNewExpr(CXXNewExpr *E) {
if (E->isPlacementNewExpr())
return CXXNewExpr::CreatePlacementNew(
- Importer.getToContext(), ToPlacementArgs[0], ToTypeIdParens, ToArraySize,
- E->getInitializationStyle(), ToInitializer, ToType, ToAllocatedTypeSourceInfo,
- ToSourceRange, ToDirectInitRange);
+ Importer.getToContext(), ToPlacementArgs[0], ToTypeIdParens,
+ ToArraySize, E->getInitializationStyle(), ToInitializer, ToType,
+ ToAllocatedTypeSourceInfo, ToSourceRange, ToDirectInitRange);
else
return CXXNewExpr::Create(
Importer.getToContext(), E->isGlobalNew(), ToOperatorNew,
ToOperatorDelete, E->passAlignment(), E->doesUsualArrayDeleteWantSize(),
- ToPlacementArgs, ToTypeIdParens, ToArraySize, E->getInitializationStyle(),
- ToInitializer, ToType, ToAllocatedTypeSourceInfo, ToSourceRange,
- ToDirectInitRange);
+ ToPlacementArgs, ToTypeIdParens, ToArraySize,
+ E->getInitializationStyle(), ToInitializer, ToType,
+ ToAllocatedTypeSourceInfo, ToSourceRange, ToDirectInitRange);
}
ExpectedStmt ASTNodeImporter::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 7c7f4c2f31542b9..e47ddc4ab083ce8 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -235,16 +235,17 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
setDependence(computeDependence(this));
}
-CXXNewExpr::CXXNewExpr(Expr *PlacementArg,
- SourceRange TypeIdParens, std::optional<Expr *> ArraySize,
- CXXNewInitializationStyle InitializationStyle, Expr *Initializer,
- QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
+CXXNewExpr::CXXNewExpr(Expr *PlacementArg, SourceRange TypeIdParens,
+ std::optional<Expr *> ArraySize,
+ CXXNewInitializationStyle InitializationStyle,
+ Expr *Initializer, QualType Ty,
+ TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
SourceRange DirectInitRange)
: CXXNewExpr(true, nullptr, nullptr, false, false,
ArrayRef<Expr *>(&PlacementArg, 1), TypeIdParens, ArraySize,
- InitializationStyle, Initializer, Ty,
- AllocatedTypeInfo, Range, DirectInitRange) {
- CXXNewExprBits.IsPlacementNewExpr = true;
+ InitializationStyle, Initializer, Ty, AllocatedTypeInfo, Range,
+ DirectInitRange) {
+ CXXNewExprBits.IsPlacementNewExpr = true;
}
CXXNewExpr::CXXNewExpr(EmptyShell Empty, bool IsArray,
@@ -279,22 +280,20 @@ CXXNewExpr *CXXNewExpr::Create(
}
CXXNewExpr *CXXNewExpr::CreatePlacementNew(
- const ASTContext &Ctx, Expr *PlacementArg,
- SourceRange TypeIdParens, std::optional<Expr *> ArraySize,
+ const ASTContext &Ctx, Expr *PlacementArg, SourceRange TypeIdParens,
+ std::optional<Expr *> ArraySize,
CXXNewInitializationStyle InitializationStyle, Expr *Initializer,
QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
SourceRange DirectInitRange) {
bool IsArray = ArraySize.has_value();
bool HasInit = Initializer != nullptr;
bool IsParenTypeId = TypeIdParens.isValid();
- void *Mem =
- Ctx.Allocate(totalSizeToAlloc<Stmt *, SourceRange>(
- IsArray + HasInit + 1, IsParenTypeId),
- alignof(CXXNewExpr));
+ void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *, SourceRange>(
+ IsArray + HasInit + 1, IsParenTypeId),
+ alignof(CXXNewExpr));
return new (Mem)
- CXXNewExpr(PlacementArg, TypeIdParens,
- ArraySize, InitializationStyle, Initializer, Ty,
- AllocatedTypeInfo, Range, DirectInitRange);
+ CXXNewExpr(PlacementArg, TypeIdParens, ArraySize, InitializationStyle,
+ Initializer, Ty, AllocatedTypeInfo, Range, DirectInitRange);
}
CXXNewExpr *CXXNewExpr::CreateEmpty(const ASTContext &Ctx, bool IsArray,
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 7652e22a6a51b4f..8ee1887c6ccf98a 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -9751,7 +9751,8 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
bool IsNothrow = false;
bool IsPlacement = false;
- if (E->isReservedPlacementNew() && Info.CurrentCall->isStdFunction() && !E->isArray()) {
+ if (E->isReservedPlacementNew() && Info.CurrentCall->isStdFunction() &&
+ !E->isArray()) {
// FIXME Support array placement new.
assert(E->getNumPlacementArgs() == 1);
if (!EvaluatePointer(E->getPlacementArg(0), Result, Info))
@@ -9759,7 +9760,8 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
if (Result.Designator.Invalid)
return false;
IsPlacement = true;
- } else if (E->isPlacementNewExpr() || !OperatorNew->isReplaceableGlobalAllocationFunction()) {
+ } else if (E->isPlacementNewExpr() ||
+ !OperatorNew->isReplaceableGlobalAllocationFunction()) {
Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
<< isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
return false;
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 93ba4a060342a22..f05f5168119aec6 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -604,12 +604,13 @@ class RuntimeInterfaceBuilder
SourceLocation(), Args, SourceLocation());
}
Expr *Args[] = {AllocCall.get()};
- ExprResult CXXNewCall = S.BuildCXXNew(
- E->getSourceRange(),
- /*UseGlobal=*/true, /*IsPlacementNewExpr=*/false,
- /*PlacementLParen=*/SourceLocation(), Args, /*PlacementRParen=*/SourceLocation(),
- /*TypeIdParens=*/SourceRange(), TSI->getType(), TSI, std::nullopt,
- E->getSourceRange(), E);
+ ExprResult CXXNewCall =
+ S.BuildCXXNew(E->getSourceRange(),
+ /*UseGlobal=*/true, /*IsPlacementNewExpr=*/false,
+ /*PlacementLParen=*/SourceLocation(), Args,
+ /*PlacementRParen=*/SourceLocation(),
+ /*TypeIdParens=*/SourceRange(), TSI->getType(), TSI,
+ std::nullopt, E->getSourceRange(), E);
assert(!CXXNewCall.isInvalid() &&
"Can't create runtime placement new call!");
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 18b2fd86e566e5c..c89dfff16c12dde 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -5456,8 +5456,8 @@ bool Parser::isTypeSpecifierQualifier() {
return isTypeSpecifierQualifier();
case tok::coloncolon: // ::foo::bar
- if (NextToken().is(tok::kw_new) || // ::new
- NextToken().is(tok::kw_delete) || // ::delete
+ if (NextToken().is(tok::kw_new) || // ::new
+ NextToken().is(tok::kw_delete) || // ::delete
NextToken().is(tok::kw__placement_new)) // ::_placement_new
return false;
@@ -5650,8 +5650,8 @@ bool Parser::isDeclarationSpecifier(
case tok::coloncolon: // ::foo::bar
if (!getLangOpts().CPlusPlus)
return false;
- if (NextToken().is(tok::kw_new) || // ::new
- NextToken().is(tok::kw_delete) || // ::delete
+ if (NextToken().is(tok::kw_new) || // ::new
+ NextToken().is(tok::kw_delete) || // ::delete
NextToken().is(tok::kw__placement_new)) // ::_placement_new
return false;
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index f21680834cfc531..1d3433f2d564dca 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -186,7 +186,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
if (Tok.is(tok::coloncolon)) {
// ::new and ::delete aren't nested-name-specifiers.
tok::TokenKind NextKind = NextToken().getKind();
- if (NextKind == tok::kw_new || NextKind == tok::kw_delete || NextKind == tok::kw__placement_new)
+ if (NextKind == tok::kw_new || NextKind == tok::kw_delete ||
+ NextKind == tok::kw__placement_new)
return false;
if (NextKind == tok::l_brace) {
@@ -3171,7 +3172,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
///
ExprResult
Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
- assert((Tok.is(tok::kw_new) || Tok.is(tok::kw__placement_new)) && "expected 'new' token");
+ assert((Tok.is(tok::kw_new) || Tok.is(tok::kw__placement_new)) &&
+ "expected 'new' token");
const bool IsPlacementNewExpr = Tok.is(tok::kw__placement_new);
ConsumeToken(); // Consume 'new'
@@ -3308,8 +3310,8 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
if (Initializer.isInvalid())
return Initializer;
- return Actions.ActOnCXXNew(Start, UseGlobal, IsPlacementNewExpr, PlacementLParen,
- PlacementArgs, PlacementRParen,
+ return Actions.ActOnCXXNew(Start, UseGlobal, IsPlacementNewExpr,
+ PlacementLParen, PlacementArgs, PlacementRParen,
TypeIdParens, DeclaratorInfo, Initializer.get());
}
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 623e3eb4ed70316..7d7a044a6b161d3 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -1444,8 +1444,8 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
case tok::coloncolon: { // ::foo::bar
const Token &Next = NextToken();
- if (Next.isOneOf(tok::kw_new, // ::new
- tok::kw_delete, // ::delete
+ if (Next.isOneOf(tok::kw_new, // ::new
+ tok::kw_delete, // ::delete
tok::kw__placement_new)) // ::_placement_new
return TPResult::False;
[[fallthrough]];
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index b8e606b3a45b965..cf015caffae80ca 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1875,10 +1875,10 @@ static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc,
/// \param Initializer The initializing expression or initializer-list, or null
/// if there is none.
ExprResult
-Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, bool IsPlacementNewExpr,
- SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
- SourceLocation PlacementRParen, SourceRange TypeIdParens,
- Declarator &D, Expr *Initializer) {
+Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
+ bool IsPlacementNewExpr, SourceLocation PlacementLParen,
+ MultiExprArg PlacementArgs, SourceLocation PlacementRParen,
+ SourceRange TypeIdParens, Declarator &D, Expr *Initializer) {
std::optional<Expr *> ArraySize;
// If the specified type is an array, unwrap it and save the expression.
if (D.getNumTypeObjects() > 0 &&
@@ -1940,10 +1940,10 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, bool IsPlacementNewEx
if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer))
DirectInitRange = List->getSourceRange();
- return BuildCXXNew(SourceRange(StartLoc, D.getEndLoc()), UseGlobal, IsPlacementNewExpr,
- PlacementLParen, PlacementArgs, PlacementRParen,
- TypeIdParens, AllocType, TInfo, ArraySize, DirectInitRange,
- Initializer);
+ return BuildCXXNew(SourceRange(StartLoc, D.getEndLoc()), UseGlobal,
+ IsPlacementNewExpr, PlacementLParen, PlacementArgs,
+ PlacementRParen, TypeIdParens, AllocType, TInfo, ArraySize,
+ DirectInitRange, Initializer);
}
static bool isLegalArrayNewInitializer(CXXNewInitializationStyle Style,
@@ -1997,14 +1997,13 @@ void Sema::diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD,
}
}
-ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, bool IsPlacementNewExpr,
- SourceLocation PlacementLParen,
- MultiExprArg PlacementArgs,
- SourceLocation PlacementRParen,
- SourceRange TypeIdParens, QualType AllocType,
- TypeSourceInfo *AllocTypeInfo,
- std::optional<Expr *> ArraySize,
- SourceRange DirectInitRange, Expr *Initializer) {
+ExprResult
+Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, bool IsPlacementNewExpr,
+ SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen, SourceRange TypeIdParens,
+ QualType AllocType, TypeSourceInfo *AllocTypeInfo,
+ std::optional<Expr *> ArraySize, SourceRange DirectInitRange,
+ Expr *Initializer) {
SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange();
SourceLocation StartLoc = Range.getBegin();
@@ -2286,7 +2285,9 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, bool IsPlacement
bool PassAlignment = getLangOpts().AlignedAllocation &&
Alignment > NewAlignment;
- bool HaveDependentPlacementTypes = AllocType->isDependentType() || Expr::hasAnyTypeDependentArguments(PlacementArgs);
+ bool HaveDependentPlacementTypes =
+ AllocType->isDependentType() ||
+ Expr::hasAnyTypeDependentArguments(PlacementArgs);
AllocationFunctionScope Scope = UseGlobal ? AFS_Global : AFS_Both;
if (!HaveDependentPlacementTypes && !IsPlacementNewExpr &&
@@ -2308,10 +2309,12 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, bool IsPlacement
assert(UseGlobal);
QualType VoidPtr = Context.getPointerType(Context.VoidTy);
- InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, VoidPtr, false);
- ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), PlacementArgs[0], false, false);
+ InitializedEntity Entity =
+ InitializedEntity::InitializeParameter(Context, VoidPtr, false);
+ ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(),
+ PlacementArgs[0], false, false);
if (ArgE.isInvalid())
- return ExprError();
+ return ExprError();
Expr *Arg = ArgE.getAs<Expr>();
CheckArrayAccess(Arg);
@@ -2499,9 +2502,9 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, bool IsPlacement
}
if (IsPlacementNewExpr)
- return CXXNewExpr::CreatePlacementNew(Context, PlacementArgs[0], TypeIdParens, ArraySize,
- InitStyle, Initializer, ResultType, AllocTypeInfo,
- Range, DirectInitRange);
+ return CXXNewExpr::CreatePlacementNew(
+ Context, PlacementArgs[0], TypeIdParens, ArraySize, InitStyle,
+ Initializer, ResultType, AllocTypeInfo, Range, DirectInitRange);
else
return CXXNewExpr::Create(Context, UseGlobal, OperatorNew, OperatorDelete,
PassAlignment, UsualArrayDeleteWantsSize,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 5fc64fa50dd431b..0c6abd7cad1b9ee 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3343,7 +3343,8 @@ class TreeTransform {
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildCXXNewExpr(SourceLocation StartLoc, bool UseGlobal, bool IsPlacementNewExpr,
+ ExprResult RebuildCXXNewExpr(SourceLocation StartLoc, bool UseGlobal,
+ bool IsPlacementNewExpr,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
@@ -3351,16 +3352,10 @@ class TreeTransform {
TypeSourceInfo *AllocatedTypeInfo,
std::optional<Expr *> ArraySize,
SourceRange DirectInitRange, Expr *Initializer) {
- return getSema().BuildCXXNew(StartLoc, UseGlobal, IsPlacementNewExpr,
- PlacementLParen,
- PlacementArgs,
- PlacementRParen,
- TypeIdParens,
- AllocatedType,
- AllocatedTypeInfo,
- ArraySize,
- DirectInitRange,
- Initializer);
+ return getSema().BuildCXXNew(
+ StartLoc, UseGlobal, IsPlacementNewExpr, PlacementLParen, PlacementArgs,
+ PlacementRParen, TypeIdParens, AllocatedType, AllocatedTypeInfo,
+ ArraySize, DirectInitRange, Initializer);
}
/// Build a new C++ "delete" expression.
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 339b26d44cc8ad0..16cd95dfce36efe 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1047,7 +1047,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// where new can return NULL. If we end up supporting that option, we can
// consider adding a check for it here.
// C++11 [basic.stc.dynamic.allocation]p3.
- if (const auto *ProtoType = FD ? FD->getType()->getAs<FunctionProtoType>() : nullptr)
+ if (const auto *ProtoType =
+ FD ? FD->getType()->getAs<FunctionProtoType>() : nullptr)
if (!ProtoType->isNothrow())
if (auto dSymVal = symVal.getAs<DefinedOrUnknownSVal>())
State = State->assume(*dSymVal, true);
>From 4f33aa02dfe2997f174a5c6994f0d70129700868 Mon Sep 17 00:00:00 2001
From: MaxEW707 <82551778+MaxEW707 at users.noreply.github.com>
Date: Tue, 14 Nov 2023 19:24:42 -0500
Subject: [PATCH 3/4] fix formatting errors
---
clang/lib/AST/ExprConstant.cpp | 4 ++--
clang/lib/Parse/ParseDecl.cpp | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 8ee1887c6ccf98a..ecf761feca30f6e 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -3185,8 +3185,8 @@ static bool HandleLValueIndirectMember(EvalInfo &Info, const Expr *E,
}
/// Get the size of the given type in char units.
-static bool HandleSizeof(EvalInfo &Info, SourceLocation Loc,
- QualType Type, CharUnits &Size) {
+static bool HandleSizeof(EvalInfo &Info, SourceLocation Loc, QualType Type,
+ CharUnits &Size) {
// sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
// extension.
if (Type->isVoidType() || Type->isFunctionType()) {
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index c89dfff16c12dde..bca29fc83b540d5 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3295,7 +3295,7 @@ static void SetupFixedPointError(const LangOptions &LangOpts,
bool &isInvalid) {
assert(!LangOpts.FixedPoint);
DiagID = diag::err_fixed_point_not_enabled;
- PrevSpec = ""; // Not used by diagnostic
+ PrevSpec = ""; // Not used by diagnostic
isInvalid = true;
}
>From a87aa5ff35f3d012b45d8bc65b7b2572f3b6685e Mon Sep 17 00:00:00 2001
From: MaxEW707 <82551778+MaxEW707 at users.noreply.github.com>
Date: Sat, 18 Nov 2023 16:32:40 -0500
Subject: [PATCH 4/4] fix unittest
---
clang/lib/Sema/SemaExprCXX.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index cf015caffae80ca..0c99b6317f3c5a9 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2304,6 +2304,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, bool IsPlacementNewExpr,
UsualArrayDeleteWantsSize =
doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType);
+ SmallVector<Expr *, 8> AllPlaceArgs;
if (IsPlacementNewExpr && !HaveDependentPlacementTypes) {
assert(PlacementArgs.size() == 1);
assert(UseGlobal);
@@ -2324,7 +2325,6 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, bool IsPlacementNewExpr,
auto *Proto = OperatorNew->getType()->castAs<FunctionProtoType>();
VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction
: VariadicDoesNotApply;
- SmallVector<Expr *, 8> AllPlaceArgs;
// We've already converted the placement args, just fill in any default
// arguments. Skip the first parameter because we don't have a corresponding
More information about the flang-commits
mailing list