Skip to content

Commit b0561b3

Browse files
committed
[NFC] Refactor representation of materialized temporaries
Summary: this patch refactor representation of materialized temporaries to prevent an issue raised by rsmith in https://reviews.llvm.org/D63640#inline-612718 Reviewers: rsmith, martong, shafik Reviewed By: rsmith Subscribers: thakis, sammccall, ilya-biryukov, rnkovacs, arphaman, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D69360
1 parent dd471db commit b0561b3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+333
-175
lines changed

clang-tools-extra/clang-tidy/abseil/StrCatAppendCheck.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ AST_MATCHER_P(Stmt, IgnoringTemporaries, ast_matchers::internal::Matcher<Stmt>,
2424
const Stmt *E = &Node;
2525
while (true) {
2626
if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
27-
E = MTE->getTemporary();
27+
E = MTE->getSubExpr();
2828
if (const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
2929
E = BTE->getSubExpr();
3030
if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E))

clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ buildBindArguments(const MatchFinder::MatchResult &Result, const CallExpr *C) {
5353
const Expr *E = C->getArg(I);
5454
BindArgument B;
5555
if (const auto *M = dyn_cast<MaterializeTemporaryExpr>(E)) {
56-
const auto *TE = M->GetTemporaryExpr();
56+
const auto *TE = M->getSubExpr();
5757
B.Kind = isa<CallExpr>(TE) ? BK_CallExpr : BK_Temporary;
5858
}
5959

clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ const Expr *digThroughConstructors(const Expr *E) {
177177
return nullptr;
178178
E = ConstructExpr->getArg(0);
179179
if (const auto *Temp = dyn_cast<MaterializeTemporaryExpr>(E))
180-
E = Temp->GetTemporaryExpr();
180+
E = Temp->getSubExpr();
181181
return digThroughConstructors(E);
182182
}
183183
return E;

clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ void ImplicitConversionInLoopCheck::check(
7878
// iterator returns a value instead of a reference, and the loop variable
7979
// is a reference. This situation is fine (it probably produces the same
8080
// code at the end).
81-
if (IsNonTrivialImplicitCast(Materialized->getTemporary()))
81+
if (IsNonTrivialImplicitCast(Materialized->getSubExpr()))
8282
ReportAndFix(Result.Context, VD, OperatorCall);
8383
}
8484

clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ void NonConstParameterCheck::markCanNotBeConst(const Expr *E,
202202
} else if (const auto *Constr = dyn_cast<CXXConstructExpr>(E)) {
203203
for (const auto *Arg : Constr->arguments()) {
204204
if (const auto *M = dyn_cast<MaterializeTemporaryExpr>(Arg))
205-
markCanNotBeConst(cast<Expr>(M->getTemporary()), CanNotBeConst);
205+
markCanNotBeConst(cast<Expr>(M->getSubExpr()), CanNotBeConst);
206206
}
207207
} else if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
208208
for (unsigned I = 0U; I < ILE->getNumInits(); ++I)

clang/include/clang/AST/ASTContext.h

-11
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
272272
/// Mapping from __block VarDecls to BlockVarCopyInit.
273273
llvm::DenseMap<const VarDecl *, BlockVarCopyInit> BlockVarCopyInits;
274274

275-
/// Mapping from materialized temporaries with static storage duration
276-
/// that appear in constant initializers to their evaluated values. These are
277-
/// allocated in a std::map because their address must be stable.
278-
llvm::DenseMap<const MaterializeTemporaryExpr *, APValue *>
279-
MaterializedTemporaryValues;
280-
281275
/// Used to cleanups APValues stored in the AST.
282276
mutable llvm::SmallVector<APValue *, 0> APValueCleanups;
283277

@@ -2827,11 +2821,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
28272821
/// index of the parameter when it exceeds the size of the normal bitfield.
28282822
unsigned getParameterIndex(const ParmVarDecl *D) const;
28292823

2830-
/// Get the storage for the constant value of a materialized temporary
2831-
/// of static storage duration.
2832-
APValue *getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,
2833-
bool MayCreate);
2834-
28352824
/// Return a string representing the human readable name for the specified
28362825
/// function declaration or file name. Used by SourceLocExpr and
28372826
/// PredefinedExpr to cache evaluated results.

clang/include/clang/AST/DeclCXX.h

+74
Original file line numberDiff line numberDiff line change
@@ -3052,6 +3052,80 @@ class NamespaceAliasDecl : public NamedDecl,
30523052
static bool classofKind(Kind K) { return K == NamespaceAlias; }
30533053
};
30543054

3055+
/// Implicit declaration of a temporary that was materialized by
3056+
/// a MaterializeTemporaryExpr and lifetime-extended by a declaration
3057+
class LifetimeExtendedTemporaryDecl final : public Decl {
3058+
friend class MaterializeTemporaryExpr;
3059+
friend class ASTDeclReader;
3060+
3061+
Stmt *ExprWithTemporary = nullptr;
3062+
3063+
/// The declaration which lifetime-extended this reference, if any.
3064+
/// Either a VarDecl, or (for a ctor-initializer) a FieldDecl.
3065+
ValueDecl *ExtendingDecl = nullptr;
3066+
unsigned ManglingNumber;
3067+
3068+
mutable APValue *Value = nullptr;
3069+
3070+
virtual void anchor();
3071+
3072+
LifetimeExtendedTemporaryDecl(Expr *Temp, ValueDecl *EDecl, unsigned Mangling)
3073+
: Decl(Decl::LifetimeExtendedTemporary, EDecl->getDeclContext(),
3074+
EDecl->getLocation()),
3075+
ExprWithTemporary(Temp), ExtendingDecl(EDecl),
3076+
ManglingNumber(Mangling) {}
3077+
3078+
LifetimeExtendedTemporaryDecl(EmptyShell)
3079+
: Decl(Decl::LifetimeExtendedTemporary, EmptyShell{}) {}
3080+
3081+
public:
3082+
static LifetimeExtendedTemporaryDecl *Create(Expr *Temp, ValueDecl *EDec,
3083+
unsigned Mangling) {
3084+
return new (EDec->getASTContext(), EDec->getDeclContext())
3085+
LifetimeExtendedTemporaryDecl(Temp, EDec, Mangling);
3086+
}
3087+
static LifetimeExtendedTemporaryDecl *CreateDeserialized(ASTContext &C,
3088+
unsigned ID) {
3089+
return new (C, ID) LifetimeExtendedTemporaryDecl(EmptyShell{});
3090+
}
3091+
3092+
ValueDecl *getExtendingDecl() { return ExtendingDecl; }
3093+
const ValueDecl *getExtendingDecl() const { return ExtendingDecl; }
3094+
3095+
/// Retrieve the storage duration for the materialized temporary.
3096+
StorageDuration getStorageDuration() const;
3097+
3098+
/// Retrieve the expression to which the temporary materialization conversion
3099+
/// was applied. This isn't necessarily the initializer of the temporary due
3100+
/// to the C++98 delayed materialization rules, but
3101+
/// skipRValueSubobjectAdjustments can be used to find said initializer within
3102+
/// the subexpression.
3103+
Expr *getTemporaryExpr() { return cast<Expr>(ExprWithTemporary); }
3104+
const Expr *getTemporaryExpr() const { return cast<Expr>(ExprWithTemporary); }
3105+
3106+
unsigned getManglingNumber() const { return ManglingNumber; }
3107+
3108+
/// Get the storage for the constant value of a materialized temporary
3109+
/// of static storage duration.
3110+
APValue *getOrCreateValue(bool MayCreate) const;
3111+
3112+
APValue *getValue() const { return Value; }
3113+
3114+
// Iterators
3115+
Stmt::child_range childrenExpr() {
3116+
return Stmt::child_range(&ExprWithTemporary, &ExprWithTemporary + 1);
3117+
}
3118+
3119+
Stmt::const_child_range childrenExpr() const {
3120+
return Stmt::const_child_range(&ExprWithTemporary, &ExprWithTemporary + 1);
3121+
}
3122+
3123+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
3124+
static bool classofKind(Kind K) {
3125+
return K == Decl::LifetimeExtendedTemporary;
3126+
}
3127+
};
3128+
30553129
/// Represents a shadow declaration introduced into a scope by a
30563130
/// (resolved) using declaration.
30573131
///

clang/include/clang/AST/ExprCXX.h

+50-56
Original file line numberDiff line numberDiff line change
@@ -4421,70 +4421,66 @@ class MaterializeTemporaryExpr : public Expr {
44214421
friend class ASTStmtReader;
44224422
friend class ASTStmtWriter;
44234423

4424-
struct ExtraState {
4425-
/// The temporary-generating expression whose value will be
4426-
/// materialized.
4427-
Stmt *Temporary;
4428-
4429-
/// The declaration which lifetime-extended this reference, if any.
4430-
/// Either a VarDecl, or (for a ctor-initializer) a FieldDecl.
4431-
const ValueDecl *ExtendingDecl;
4432-
4433-
unsigned ManglingNumber;
4434-
};
4435-
llvm::PointerUnion<Stmt *, ExtraState *> State;
4424+
llvm::PointerUnion<Stmt *, LifetimeExtendedTemporaryDecl *> State;
44364425

44374426
public:
44384427
MaterializeTemporaryExpr(QualType T, Expr *Temporary,
4439-
bool BoundToLvalueReference)
4440-
: Expr(MaterializeTemporaryExprClass, T,
4441-
BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary,
4442-
Temporary->isTypeDependent(), Temporary->isValueDependent(),
4443-
Temporary->isInstantiationDependent(),
4444-
Temporary->containsUnexpandedParameterPack()),
4445-
State(Temporary) {}
4428+
bool BoundToLvalueReference,
4429+
LifetimeExtendedTemporaryDecl *MTD = nullptr);
44464430

44474431
MaterializeTemporaryExpr(EmptyShell Empty)
44484432
: Expr(MaterializeTemporaryExprClass, Empty) {}
44494433

4450-
Stmt *getTemporary() const {
4451-
return State.is<Stmt *>() ? State.get<Stmt *>()
4452-
: State.get<ExtraState *>()->Temporary;
4453-
}
4454-
44554434
/// Retrieve the temporary-generating subexpression whose value will
44564435
/// be materialized into a glvalue.
4457-
Expr *GetTemporaryExpr() const { return static_cast<Expr *>(getTemporary()); }
4436+
Expr *getSubExpr() const {
4437+
return cast<Expr>(
4438+
State.is<Stmt *>()
4439+
? State.get<Stmt *>()
4440+
: State.get<LifetimeExtendedTemporaryDecl *>()->getTemporaryExpr());
4441+
}
44584442

44594443
/// Retrieve the storage duration for the materialized temporary.
44604444
StorageDuration getStorageDuration() const {
4461-
const ValueDecl *ExtendingDecl = getExtendingDecl();
4462-
if (!ExtendingDecl)
4463-
return SD_FullExpression;
4464-
// FIXME: This is not necessarily correct for a temporary materialized
4465-
// within a default initializer.
4466-
if (isa<FieldDecl>(ExtendingDecl))
4467-
return SD_Automatic;
4468-
// FIXME: This only works because storage class specifiers are not allowed
4469-
// on decomposition declarations.
4470-
if (isa<BindingDecl>(ExtendingDecl))
4471-
return ExtendingDecl->getDeclContext()->isFunctionOrMethod()
4472-
? SD_Automatic
4473-
: SD_Static;
4474-
return cast<VarDecl>(ExtendingDecl)->getStorageDuration();
4445+
return State.is<Stmt *>() ? SD_FullExpression
4446+
: State.get<LifetimeExtendedTemporaryDecl *>()
4447+
->getStorageDuration();
4448+
}
4449+
4450+
/// Get the storage for the constant value of a materialized temporary
4451+
/// of static storage duration.
4452+
APValue *getOrCreateValue(bool MayCreate) const {
4453+
assert(State.is<LifetimeExtendedTemporaryDecl *>() &&
4454+
"the temporary has not been lifetime extended");
4455+
return State.get<LifetimeExtendedTemporaryDecl *>()->getOrCreateValue(
4456+
MayCreate);
4457+
}
4458+
4459+
LifetimeExtendedTemporaryDecl *getLifetimeExtendedTemporaryDecl() {
4460+
return State.dyn_cast<LifetimeExtendedTemporaryDecl *>();
4461+
}
4462+
const LifetimeExtendedTemporaryDecl *
4463+
getLifetimeExtendedTemporaryDecl() const {
4464+
return State.dyn_cast<LifetimeExtendedTemporaryDecl *>();
44754465
}
44764466

44774467
/// Get the declaration which triggered the lifetime-extension of this
44784468
/// temporary, if any.
4479-
const ValueDecl *getExtendingDecl() const {
4469+
ValueDecl *getExtendingDecl() {
44804470
return State.is<Stmt *>() ? nullptr
4481-
: State.get<ExtraState *>()->ExtendingDecl;
4471+
: State.get<LifetimeExtendedTemporaryDecl *>()
4472+
->getExtendingDecl();
4473+
}
4474+
const ValueDecl *getExtendingDecl() const {
4475+
return const_cast<MaterializeTemporaryExpr *>(this)->getExtendingDecl();
44824476
}
44834477

4484-
void setExtendingDecl(const ValueDecl *ExtendedBy, unsigned ManglingNumber);
4478+
void setExtendingDecl(ValueDecl *ExtendedBy, unsigned ManglingNumber);
44854479

44864480
unsigned getManglingNumber() const {
4487-
return State.is<Stmt *>() ? 0 : State.get<ExtraState *>()->ManglingNumber;
4481+
return State.is<Stmt *>() ? 0
4482+
: State.get<LifetimeExtendedTemporaryDecl *>()
4483+
->getManglingNumber();
44884484
}
44894485

44904486
/// Determine whether this materialized temporary is bound to an
@@ -4494,11 +4490,11 @@ class MaterializeTemporaryExpr : public Expr {
44944490
}
44954491

44964492
SourceLocation getBeginLoc() const LLVM_READONLY {
4497-
return getTemporary()->getBeginLoc();
4493+
return getSubExpr()->getBeginLoc();
44984494
}
44994495

45004496
SourceLocation getEndLoc() const LLVM_READONLY {
4501-
return getTemporary()->getEndLoc();
4497+
return getSubExpr()->getEndLoc();
45024498
}
45034499

45044500
static bool classof(const Stmt *T) {
@@ -4507,20 +4503,18 @@ class MaterializeTemporaryExpr : public Expr {
45074503

45084504
// Iterators
45094505
child_range children() {
4510-
if (State.is<Stmt *>())
4511-
return child_range(State.getAddrOfPtr1(), State.getAddrOfPtr1() + 1);
4512-
4513-
auto ES = State.get<ExtraState *>();
4514-
return child_range(&ES->Temporary, &ES->Temporary + 1);
4506+
return State.is<Stmt *>()
4507+
? child_range(State.getAddrOfPtr1(), State.getAddrOfPtr1() + 1)
4508+
: State.get<LifetimeExtendedTemporaryDecl *>()->childrenExpr();
45154509
}
45164510

45174511
const_child_range children() const {
4518-
if (State.is<Stmt *>())
4519-
return const_child_range(State.getAddrOfPtr1(),
4520-
State.getAddrOfPtr1() + 1);
4521-
4522-
auto ES = State.get<ExtraState *>();
4523-
return const_child_range(&ES->Temporary, &ES->Temporary + 1);
4512+
return State.is<Stmt *>()
4513+
? const_child_range(State.getAddrOfPtr1(),
4514+
State.getAddrOfPtr1() + 1)
4515+
: const_cast<const LifetimeExtendedTemporaryDecl *>(
4516+
State.get<LifetimeExtendedTemporaryDecl *>())
4517+
->childrenExpr();
45244518
}
45254519
};
45264520

clang/include/clang/AST/RecursiveASTVisitor.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -1435,6 +1435,10 @@ DEF_TRAVERSE_DECL(CapturedDecl, {
14351435

14361436
DEF_TRAVERSE_DECL(EmptyDecl, {})
14371437

1438+
DEF_TRAVERSE_DECL(LifetimeExtendedTemporaryDecl, {
1439+
TRY_TO(TraverseStmt(D->getTemporaryExpr()));
1440+
})
1441+
14381442
DEF_TRAVERSE_DECL(FileScopeAsmDecl,
14391443
{ TRY_TO(TraverseStmt(D->getAsmString())); })
14401444

@@ -2632,10 +2636,16 @@ DEF_TRAVERSE_STMT(SizeOfPackExpr, {})
26322636
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {})
26332637
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {})
26342638
DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
2635-
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {})
26362639
DEF_TRAVERSE_STMT(CXXFoldExpr, {})
26372640
DEF_TRAVERSE_STMT(AtomicExpr, {})
26382641

2642+
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {
2643+
if (S->getLifetimeExtendedTemporaryDecl()) {
2644+
TRY_TO(TraverseLifetimeExtendedTemporaryDecl(
2645+
S->getLifetimeExtendedTemporaryDecl()));
2646+
ShouldVisitChildren = false;
2647+
}
2648+
})
26392649
// For coroutines expressions, traverse either the operand
26402650
// as written or the implied calls, depending on what the
26412651
// derived class requests.

clang/include/clang/ASTMatchers/ASTMatchers.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -6621,8 +6621,8 @@ AST_MATCHER_P(Expr, ignoringElidableConstructorCall,
66216621
if (CtorExpr->isElidable()) {
66226622
if (const auto *MaterializeTemp =
66236623
dyn_cast<MaterializeTemporaryExpr>(CtorExpr->getArg(0))) {
6624-
return InnerMatcher.matches(*MaterializeTemp->GetTemporaryExpr(),
6625-
Finder, Builder);
6624+
return InnerMatcher.matches(*MaterializeTemp->getSubExpr(), Finder,
6625+
Builder);
66266626
}
66276627
}
66286628
}

clang/include/clang/Basic/DeclNodes.td

+1
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,5 @@ def OMPThreadPrivate : DeclNode<Decl>;
100100
def OMPAllocate : DeclNode<Decl>;
101101
def OMPRequires : DeclNode<Decl>;
102102
def Empty : DeclNode<Decl>;
103+
def LifetimeExtendedTemporary : DeclNode<Decl>;
103104

clang/include/clang/Sema/Template.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -464,8 +464,9 @@ class VarDecl;
464464
#define OBJCPROPERTY(DERIVED, BASE)
465465
#define OBJCPROPERTYIMPL(DERIVED, BASE)
466466
#define EMPTY(DERIVED, BASE)
467+
#define LIFETIMEEXTENDEDTEMPORARY(DERIVED, BASE)
467468

468-
// Decls which use special-case instantiation code.
469+
// Decls which use special-case instantiation code.
469470
#define BLOCK(DERIVED, BASE)
470471
#define CAPTURED(DERIVED, BASE)
471472
#define IMPLICITPARAM(DERIVED, BASE)

clang/include/clang/Serialization/ASTBitCodes.h

+3
Original file line numberDiff line numberDiff line change
@@ -1537,6 +1537,9 @@ namespace serialization {
15371537
/// An EmptyDecl record.
15381538
DECL_EMPTY,
15391539

1540+
/// An LifetimeExtendedTemporaryDecl record.
1541+
DECL_LIFETIME_EXTENDED_TEMPORARY,
1542+
15401543
/// An ObjCTypeParamDecl record.
15411544
DECL_OBJC_TYPE_PARAM,
15421545

0 commit comments

Comments
 (0)