Skip to content

[clang][NFC] Refactor CXXNewExpr::InitializationStyle #71322

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,8 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
return false;
};
switch (New->getInitializationStyle()) {
case CXXNewExpr::NoInit: {
case CXXNewInitializationStyle::None:
case CXXNewInitializationStyle::Implicit: {
if (ArraySizeExpr.empty()) {
Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd));
} else {
Expand All @@ -334,7 +335,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
}
break;
}
case CXXNewExpr::CallInit: {
case CXXNewInitializationStyle::Call: {
// FIXME: Add fixes for constructors with parameters that can be created
// with a C++11 braced-init-list (e.g. std::vector, std::map).
// Unlike ordinal cases, braced list can not be deduced in
Expand Down Expand Up @@ -371,7 +372,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
}
break;
}
case CXXNewExpr::ListInit: {
case CXXNewInitializationStyle::List: {
// Range of the substring that we do not want to remove.
SourceRange InitRange;
if (const auto *NewConstruct = New->getConstructExpr()) {
Expand Down
48 changes: 27 additions & 21 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -2206,6 +2206,20 @@ class CXXScalarValueInitExpr : public Expr {
}
};

enum class CXXNewInitializationStyle {
/// New-expression has no initializer as written.
None,

/// New-expression has no written initializer, but has an implicit one.
Implicit,

/// New-expression has a C++98 paren-delimited initializer.
Call,

/// New-expression has a C++11 list-initializer.
List
};

/// Represents a new-expression for memory allocation and constructor
/// calls, e.g: "new CXXNewExpr(foo)".
class CXXNewExpr final
Expand Down Expand Up @@ -2259,25 +2273,12 @@ class CXXNewExpr final
return isParenTypeId();
}

public:
enum InitializationStyle {
/// New-expression has no initializer as written.
NoInit,

/// New-expression has a C++98 paren-delimited initializer.
CallInit,

/// New-expression has a C++11 list-initializer.
ListInit
};

private:
/// Build a c++ new expression.
CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
FunctionDecl *OperatorDelete, bool ShouldPassAlignment,
bool UsualArrayDeleteWantsSize, ArrayRef<Expr *> PlacementArgs,
SourceRange TypeIdParens, std::optional<Expr *> ArraySize,
InitializationStyle InitializationStyle, Expr *Initializer,
CXXNewInitializationStyle InitializationStyle, Expr *Initializer,
QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
SourceRange DirectInitRange);

Expand All @@ -2292,7 +2293,7 @@ class CXXNewExpr final
FunctionDecl *OperatorDelete, bool ShouldPassAlignment,
bool UsualArrayDeleteWantsSize, ArrayRef<Expr *> PlacementArgs,
SourceRange TypeIdParens, std::optional<Expr *> ArraySize,
InitializationStyle InitializationStyle, Expr *Initializer,
CXXNewInitializationStyle InitializationStyle, Expr *Initializer,
QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
SourceRange DirectInitRange);

Expand Down Expand Up @@ -2388,15 +2389,20 @@ class CXXNewExpr final

/// Whether this new-expression has any initializer at all.
bool hasInitializer() const {
return CXXNewExprBits.StoredInitializationStyle > 0;
switch (getInitializationStyle()) {
case CXXNewInitializationStyle::None:
return false;
case CXXNewInitializationStyle::Implicit:
case CXXNewInitializationStyle::Call:
case CXXNewInitializationStyle::List:
return true;
}
}

/// The kind of initializer this new-expression has.
InitializationStyle getInitializationStyle() const {
if (CXXNewExprBits.StoredInitializationStyle == 0)
return NoInit;
return static_cast<InitializationStyle>(
CXXNewExprBits.StoredInitializationStyle - 1);
CXXNewInitializationStyle getInitializationStyle() const {
return static_cast<CXXNewInitializationStyle>(
CXXNewExprBits.StoredInitializationStyle);
}

/// The initializer of this new-expression.
Expand Down
29 changes: 15 additions & 14 deletions clang/lib/AST/ExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
bool UsualArrayDeleteWantsSize,
ArrayRef<Expr *> PlacementArgs, SourceRange TypeIdParens,
std::optional<Expr *> ArraySize,
InitializationStyle InitializationStyle,
CXXNewInitializationStyle InitializationStyle,
Expr *Initializer, QualType Ty,
TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
SourceRange DirectInitRange)
Expand All @@ -193,15 +193,17 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
AllocatedTypeInfo(AllocatedTypeInfo), Range(Range),
DirectInitRange(DirectInitRange) {

assert((Initializer != nullptr || InitializationStyle == NoInit) &&
assert((Initializer != nullptr ||
InitializationStyle == CXXNewInitializationStyle::None ||
InitializationStyle == CXXNewInitializationStyle::Implicit) &&
"Only NoInit can have no initializer!");

CXXNewExprBits.IsGlobalNew = IsGlobalNew;
CXXNewExprBits.IsArray = ArraySize.has_value();
CXXNewExprBits.ShouldPassAlignment = ShouldPassAlignment;
CXXNewExprBits.UsualArrayDeleteWantsSize = UsualArrayDeleteWantsSize;
CXXNewExprBits.StoredInitializationStyle =
Initializer ? InitializationStyle + 1 : 0;
llvm::to_underlying(InitializationStyle);
bool IsParenTypeId = TypeIdParens.isValid();
CXXNewExprBits.IsParenTypeId = IsParenTypeId;
CXXNewExprBits.NumPlacementArgs = PlacementArgs.size();
Expand All @@ -217,10 +219,10 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
getTrailingObjects<SourceRange>()[0] = TypeIdParens;

switch (getInitializationStyle()) {
case CallInit:
case CXXNewInitializationStyle::Call:
this->Range.setEnd(DirectInitRange.getEnd());
break;
case ListInit:
case CXXNewInitializationStyle::List:
this->Range.setEnd(getInitializer()->getSourceRange().getEnd());
break;
default:
Expand All @@ -240,15 +242,14 @@ CXXNewExpr::CXXNewExpr(EmptyShell Empty, bool IsArray,
CXXNewExprBits.IsParenTypeId = IsParenTypeId;
}

CXXNewExpr *
CXXNewExpr::Create(const ASTContext &Ctx, bool IsGlobalNew,
FunctionDecl *OperatorNew, FunctionDecl *OperatorDelete,
bool ShouldPassAlignment, bool UsualArrayDeleteWantsSize,
ArrayRef<Expr *> PlacementArgs, SourceRange TypeIdParens,
std::optional<Expr *> ArraySize,
InitializationStyle InitializationStyle, Expr *Initializer,
QualType Ty, TypeSourceInfo *AllocatedTypeInfo,
SourceRange Range, SourceRange DirectInitRange) {
CXXNewExpr *CXXNewExpr::Create(
const ASTContext &Ctx, bool IsGlobalNew, FunctionDecl *OperatorNew,
FunctionDecl *OperatorDelete, bool ShouldPassAlignment,
bool UsualArrayDeleteWantsSize, ArrayRef<Expr *> PlacementArgs,
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;
unsigned NumPlacementArgs = PlacementArgs.size();
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4826,7 +4826,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
Out << '_';
mangleType(New->getAllocatedType());
if (New->hasInitializer()) {
if (New->getInitializationStyle() == CXXNewExpr::ListInit)
if (New->getInitializationStyle() == CXXNewInitializationStyle::List)
Out << "il";
else
Out << "pi";
Expand All @@ -4840,7 +4840,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
} else if (const ParenListExpr *PLE = dyn_cast<ParenListExpr>(Init)) {
for (unsigned i = 0, e = PLE->getNumExprs(); i != e; ++i)
mangleExpression(PLE->getExpr(i));
} else if (New->getInitializationStyle() == CXXNewExpr::ListInit &&
} else if (New->getInitializationStyle() ==
CXXNewInitializationStyle::List &&
isa<InitListExpr>(Init)) {
// Only take InitListExprs apart for list-initialization.
mangleInitListElements(cast<InitListExpr>(Init));
Expand Down
12 changes: 9 additions & 3 deletions clang/lib/AST/JSONNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1351,9 +1351,15 @@ void JSONNodeDumper::VisitCXXNewExpr(const CXXNewExpr *NE) {
attributeOnlyIfTrue("isArray", NE->isArray());
attributeOnlyIfTrue("isPlacement", NE->getNumPlacementArgs() != 0);
switch (NE->getInitializationStyle()) {
case CXXNewExpr::NoInit: break;
case CXXNewExpr::CallInit: JOS.attribute("initStyle", "call"); break;
case CXXNewExpr::ListInit: JOS.attribute("initStyle", "list"); break;
case CXXNewInitializationStyle::None:
case CXXNewInitializationStyle::Implicit:
break;
case CXXNewInitializationStyle::Call:
JOS.attribute("initStyle", "call");
break;
case CXXNewInitializationStyle::List:
JOS.attribute("initStyle", "list");
break;
}
if (const FunctionDecl *FD = NE->getOperatorNew())
JOS.attribute("operatorNewDecl", createBareDeclRef(FD));
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/AST/StmtPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2298,9 +2298,10 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
if (E->isParenTypeId())
OS << ")";

CXXNewExpr::InitializationStyle InitStyle = E->getInitializationStyle();
if (InitStyle != CXXNewExpr::NoInit) {
bool Bare = InitStyle == CXXNewExpr::CallInit &&
CXXNewInitializationStyle InitStyle = E->getInitializationStyle();
if (InitStyle != CXXNewInitializationStyle::None &&
InitStyle != CXXNewInitializationStyle::Implicit) {
bool Bare = InitStyle == CXXNewInitializationStyle::Call &&
!isa<ParenListExpr>(E->getInitializer());
if (Bare)
OS << "(";
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2096,7 +2096,7 @@ void StmtProfiler::VisitCXXNewExpr(const CXXNewExpr *S) {
ID.AddInteger(S->getNumPlacementArgs());
ID.AddBoolean(S->isGlobalNew());
ID.AddBoolean(S->isParenTypeId());
ID.AddInteger(S->getInitializationStyle());
ID.AddInteger(llvm::to_underlying(S->getInitializationStyle()));
}

void
Expand Down
60 changes: 33 additions & 27 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1946,7 +1946,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
Initializer);
}

static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style,
static bool isLegalArrayNewInitializer(CXXNewInitializationStyle Style,
Expr *Init) {
if (!Init)
return true;
Expand All @@ -1957,7 +1957,7 @@ static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style,
else if (CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init))
return !CCE->isListInitialization() &&
CCE->getConstructor()->isDefaultConstructor();
else if (Style == CXXNewExpr::ListInit) {
else if (Style == CXXNewInitializationStyle::List) {
assert(isa<InitListExpr>(Init) &&
"Shouldn't create list CXXConstructExprs for arrays.");
return true;
Expand Down Expand Up @@ -2008,44 +2008,49 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange();
SourceLocation StartLoc = Range.getBegin();

CXXNewExpr::InitializationStyle initStyle;
CXXNewInitializationStyle InitStyle;
if (DirectInitRange.isValid()) {
assert(Initializer && "Have parens but no initializer.");
initStyle = CXXNewExpr::CallInit;
InitStyle = CXXNewInitializationStyle::Call;
} else if (Initializer && isa<InitListExpr>(Initializer))
initStyle = CXXNewExpr::ListInit;
InitStyle = CXXNewInitializationStyle::List;
else {
assert((!Initializer || isa<ImplicitValueInitExpr>(Initializer) ||
isa<CXXConstructExpr>(Initializer)) &&
"Initializer expression that cannot have been implicitly created.");
initStyle = CXXNewExpr::NoInit;
InitStyle = CXXNewInitializationStyle::None;
}

MultiExprArg Exprs(&Initializer, Initializer ? 1 : 0);
if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) {
assert(initStyle == CXXNewExpr::CallInit && "paren init for non-call init");
assert(InitStyle == CXXNewInitializationStyle::Call &&
"paren init for non-call init");
Exprs = MultiExprArg(List->getExprs(), List->getNumExprs());
}

// C++11 [expr.new]p15:
// A new-expression that creates an object of type T initializes that
// object as follows:
InitializationKind Kind
// - If the new-initializer is omitted, the object is default-
// initialized (8.5); if no initialization is performed,
// the object has indeterminate value
= initStyle == CXXNewExpr::NoInit
? InitializationKind::CreateDefault(TypeRange.getBegin())
// - Otherwise, the new-initializer is interpreted according to
// the
// initialization rules of 8.5 for direct-initialization.
: initStyle == CXXNewExpr::ListInit
? InitializationKind::CreateDirectList(
TypeRange.getBegin(), Initializer->getBeginLoc(),
Initializer->getEndLoc())
: InitializationKind::CreateDirect(TypeRange.getBegin(),
DirectInitRange.getBegin(),
DirectInitRange.getEnd());
InitializationKind Kind = [&] {
switch (InitStyle) {
// - If the new-initializer is omitted, the object is default-
// initialized (8.5); if no initialization is performed,
// the object has indeterminate value
case CXXNewInitializationStyle::None:
case CXXNewInitializationStyle::Implicit:
return InitializationKind::CreateDefault(TypeRange.getBegin());
// - Otherwise, the new-initializer is interpreted according to the
// initialization rules of 8.5 for direct-initialization.
case CXXNewInitializationStyle::Call:
return InitializationKind::CreateDirect(TypeRange.getBegin(),
DirectInitRange.getBegin(),
DirectInitRange.getEnd());
case CXXNewInitializationStyle::List:
return InitializationKind::CreateDirectList(TypeRange.getBegin(),
Initializer->getBeginLoc(),
Initializer->getEndLoc());
}
}();

// C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for.
auto *Deduced = AllocType->getContainedDeducedType();
Expand All @@ -2066,13 +2071,14 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
return ExprError();
} else if (Deduced && !Deduced->isDeduced()) {
MultiExprArg Inits = Exprs;
bool Braced = (initStyle == CXXNewExpr::ListInit);
bool Braced = (InitStyle == CXXNewInitializationStyle::List);
if (Braced) {
auto *ILE = cast<InitListExpr>(Exprs[0]);
Inits = MultiExprArg(ILE->getInits(), ILE->getNumInits());
}

if (initStyle == CXXNewExpr::NoInit || Inits.empty())
if (InitStyle == CXXNewInitializationStyle::None ||
InitStyle == CXXNewInitializationStyle::Implicit || Inits.empty())
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
<< AllocType << TypeRange);
if (Inits.size() > 1) {
Expand Down Expand Up @@ -2396,7 +2402,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// Array 'new' can't have any initializers except empty parentheses.
// Initializer lists are also allowed, in C++11. Rely on the parser for the
// dialect distinction.
if (ArraySize && !isLegalArrayNewInitializer(initStyle, Initializer)) {
if (ArraySize && !isLegalArrayNewInitializer(InitStyle, Initializer)) {
SourceRange InitRange(Exprs.front()->getBeginLoc(),
Exprs.back()->getEndLoc());
Diag(StartLoc, diag::err_new_array_init_args) << InitRange;
Expand Down Expand Up @@ -2468,7 +2474,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,

return CXXNewExpr::Create(Context, UseGlobal, OperatorNew, OperatorDelete,
PassAlignment, UsualArrayDeleteWantsSize,
PlacementArgs, TypeIdParens, ArraySize, initStyle,
PlacementArgs, TypeIdParens, ArraySize, InitStyle,
Initializer, ResultType, AllocTypeInfo, Range,
DirectInitRange);
}
Expand Down