Skip to content

Commit

Permalink
[clang][NFC] Refactor CXXNewExpr::InitializationStyle (#71322)
Browse files Browse the repository at this point in the history
This patch converts `CXXNewExpr::InitializationStyle` into a scoped enum at namespace scope. It also affirms the status quo by adding a new enumerator to represent implicit initializer.
  • Loading branch information
Endilll committed Nov 6, 2023
1 parent e96889d commit ace4489
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 74 deletions.
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

0 comments on commit ace4489

Please sign in to comment.