Skip to content

Commit 7c44da2

Browse files
committed
Create ConstantExpr class
A ConstantExpr class represents a full expression that's in a context where a constant expression is required. This class reflects the path the evaluator took to reach the expression rather than the syntactic context in which the expression occurs. In the future, the class will be expanded to cache the result of the evaluated expression so that it's not needlessly re-evaluated Reviewed By: rsmith Differential Revision: https://reviews.llvm.org/D53475 llvm-svn: 345692
1 parent 4ff6697 commit 7c44da2

40 files changed

+187
-73
lines changed

clang/include/clang/AST/Expr.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,64 @@ class Expr : public Stmt {
868868
}
869869
};
870870

871+
//===----------------------------------------------------------------------===//
872+
// Wrapper Expressions.
873+
//===----------------------------------------------------------------------===//
874+
875+
/// FullExpr - Represents a "full-expression" node.
876+
class FullExpr : public Expr {
877+
protected:
878+
Stmt *SubExpr;
879+
880+
FullExpr(StmtClass SC, Expr *subexpr)
881+
: Expr(SC, subexpr->getType(),
882+
subexpr->getValueKind(), subexpr->getObjectKind(),
883+
subexpr->isTypeDependent(), subexpr->isValueDependent(),
884+
subexpr->isInstantiationDependent(),
885+
subexpr->containsUnexpandedParameterPack()), SubExpr(subexpr) {}
886+
FullExpr(StmtClass SC, EmptyShell Empty)
887+
: Expr(SC, Empty) {}
888+
public:
889+
const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
890+
Expr *getSubExpr() { return cast<Expr>(SubExpr); }
891+
892+
/// As with any mutator of the AST, be very careful when modifying an
893+
/// existing AST to preserve its invariants.
894+
void setSubExpr(Expr *E) { SubExpr = E; }
895+
896+
static bool classof(const Stmt *T) {
897+
return T->getStmtClass() >= firstFullExprConstant &&
898+
T->getStmtClass() <= lastFullExprConstant;
899+
}
900+
};
901+
902+
/// ConstantExpr - An expression that occurs in a constant context.
903+
struct ConstantExpr : public FullExpr {
904+
ConstantExpr(Expr *subexpr)
905+
: FullExpr(ConstantExprClass, subexpr) {}
906+
907+
/// Build an empty constant expression wrapper.
908+
explicit ConstantExpr(EmptyShell Empty)
909+
: FullExpr(ConstantExprClass, Empty) {}
910+
911+
SourceLocation getBeginLoc() const LLVM_READONLY {
912+
return SubExpr->getBeginLoc();
913+
}
914+
SourceLocation getEndLoc() const LLVM_READONLY {
915+
return SubExpr->getEndLoc();
916+
}
917+
918+
static bool classof(const Stmt *T) {
919+
return T->getStmtClass() == ConstantExprClass;
920+
}
921+
922+
// Iterators
923+
child_range children() { return child_range(&SubExpr, &SubExpr+1); }
924+
const_child_range children() const {
925+
return const_child_range(&SubExpr, &SubExpr + 1);
926+
}
927+
};
928+
871929
//===----------------------------------------------------------------------===//
872930
// Primary Expressions.
873931
//===----------------------------------------------------------------------===//

clang/include/clang/AST/ExprCXX.h

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3031,7 +3031,7 @@ class DependentScopeDeclRefExpr final
30313031
/// potentially-evaluated block literal. The lifetime of a block
30323032
/// literal is the extent of the enclosing scope.
30333033
class ExprWithCleanups final
3034-
: public Expr,
3034+
: public FullExpr,
30353035
private llvm::TrailingObjects<ExprWithCleanups, BlockDecl *> {
30363036
public:
30373037
/// The type of objects that are kept in the cleanup.
@@ -3044,8 +3044,6 @@ class ExprWithCleanups final
30443044
friend class ASTStmtReader;
30453045
friend TrailingObjects;
30463046

3047-
Stmt *SubExpr;
3048-
30493047
ExprWithCleanups(EmptyShell, unsigned NumObjects);
30503048
ExprWithCleanups(Expr *SubExpr, bool CleanupsHaveSideEffects,
30513049
ArrayRef<CleanupObject> Objects);
@@ -3070,17 +3068,10 @@ class ExprWithCleanups final
30703068
return getObjects()[i];
30713069
}
30723070

3073-
Expr *getSubExpr() { return cast<Expr>(SubExpr); }
3074-
const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
3075-
30763071
bool cleanupsHaveSideEffects() const {
30773072
return ExprWithCleanupsBits.CleanupsHaveSideEffects;
30783073
}
30793074

3080-
/// As with any mutator of the AST, be very careful
3081-
/// when modifying an existing AST to preserve its invariants.
3082-
void setSubExpr(Expr *E) { SubExpr = E; }
3083-
30843075
SourceLocation getBeginLoc() const LLVM_READONLY {
30853076
return SubExpr->getBeginLoc();
30863077
}

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,6 +2199,8 @@ DEF_TRAVERSE_STMT(ReturnStmt, {})
21992199
DEF_TRAVERSE_STMT(SwitchStmt, {})
22002200
DEF_TRAVERSE_STMT(WhileStmt, {})
22012201

2202+
DEF_TRAVERSE_STMT(ConstantExpr, {})
2203+
22022204
DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
22032205
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
22042206
TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo()));

clang/include/clang/Basic/StmtNodes.td

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ def VAArgExpr : DStmt<Expr>;
9393
def GenericSelectionExpr : DStmt<Expr>;
9494
def PseudoObjectExpr : DStmt<Expr>;
9595

96+
// Wrapper expressions
97+
def FullExpr : DStmt<Expr, 1>;
98+
def ConstantExpr : DStmt<FullExpr>;
99+
96100
// Atomic expressions
97101
def AtomicExpr : DStmt<Expr>;
98102

@@ -131,7 +135,7 @@ def DependentScopeDeclRefExpr : DStmt<Expr>;
131135
def CXXConstructExpr : DStmt<Expr>;
132136
def CXXInheritedCtorInitExpr : DStmt<Expr>;
133137
def CXXBindTemporaryExpr : DStmt<Expr>;
134-
def ExprWithCleanups : DStmt<Expr>;
138+
def ExprWithCleanups : DStmt<FullExpr>;
135139
def CXXTemporaryObjectExpr : DStmt<CXXConstructExpr>;
136140
def CXXUnresolvedConstructExpr : DStmt<Expr>;
137141
def CXXDependentScopeMemberExpr : DStmt<Expr>;

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,6 +1618,9 @@ namespace serialization {
16181618
/// A MS-style AsmStmt record.
16191619
STMT_MSASM,
16201620

1621+
/// A constant expression context.
1622+
EXPR_CONSTANT,
1623+
16211624
/// A PredefinedExpr record.
16221625
EXPR_PREDEFINED,
16231626

clang/lib/ARCMigrate/TransAutoreleasePool.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,8 @@ class AutoreleasePoolRewriter
403403
return cast<Expr>(getEssential((Stmt*)E));
404404
}
405405
static Stmt *getEssential(Stmt *S) {
406-
if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S))
407-
S = EWC->getSubExpr();
406+
if (FullExpr *FE = dyn_cast<FullExpr>(S))
407+
S = FE->getSubExpr();
408408
if (Expr *E = dyn_cast<Expr>(S))
409409
S = E->IgnoreParenCasts();
410410
return S;

clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ class RetainReleaseDeallocRemover :
253253
}
254254
while (OuterS && (isa<ParenExpr>(OuterS) ||
255255
isa<CastExpr>(OuterS) ||
256-
isa<ExprWithCleanups>(OuterS)));
256+
isa<FullExpr>(OuterS)));
257257

258258
if (!OuterS)
259259
return std::make_pair(prevStmt, nextStmt);
@@ -376,8 +376,8 @@ class RetainReleaseDeallocRemover :
376376

377377
RecContainer = StmtE;
378378
Rec = Init->IgnoreParenImpCasts();
379-
if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Rec))
380-
Rec = EWC->getSubExpr()->IgnoreParenImpCasts();
379+
if (FullExpr *FE = dyn_cast<FullExpr>(Rec))
380+
Rec = FE->getSubExpr()->IgnoreParenImpCasts();
381381
RecRange = Rec->getSourceRange();
382382
if (SM.isMacroArgExpansion(RecRange.getBegin()))
383383
RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin()));

clang/lib/ARCMigrate/TransUnbridgedCasts.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
372372
Stmt *parent = E;
373373
do {
374374
parent = StmtMap->getParentIgnoreParenImpCasts(parent);
375-
} while (parent && isa<ExprWithCleanups>(parent));
375+
} while (parent && isa<FullExpr>(parent));
376376

377377
if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
378378
std::string note = "remove the cast and change return type of function "

clang/lib/ARCMigrate/Transforms.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ bool trans::isPlusOneAssign(const BinaryOperator *E) {
7474
bool trans::isPlusOne(const Expr *E) {
7575
if (!E)
7676
return false;
77-
if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E))
78-
E = EWC->getSubExpr();
77+
if (const FullExpr *FE = dyn_cast<FullExpr>(E))
78+
E = FE->getSubExpr();
7979

8080
if (const ObjCMessageExpr *
8181
ME = dyn_cast<ObjCMessageExpr>(E->IgnoreParenCasts()))

clang/lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2576,7 +2576,7 @@ Expr *ParmVarDecl::getDefaultArg() {
25762576
"Default argument is not yet instantiated!");
25772577

25782578
Expr *Arg = getInit();
2579-
if (auto *E = dyn_cast_or_null<ExprWithCleanups>(Arg))
2579+
if (auto *E = dyn_cast_or_null<FullExpr>(Arg))
25802580
return E->getSubExpr();
25812581

25822582
return Arg;

clang/lib/AST/Expr.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3126,6 +3126,11 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
31263126
// These never have a side-effect.
31273127
return false;
31283128

3129+
case ConstantExprClass:
3130+
// FIXME: Move this into the "return false;" block above.
3131+
return cast<ConstantExpr>(this)->getSubExpr()->HasSideEffects(
3132+
Ctx, IncludePossibleEffects);
3133+
31293134
case CallExprClass:
31303135
case CXXOperatorCallExprClass:
31313136
case CXXMemberCallExprClass:

clang/lib/AST/ExprCXX.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,12 +1044,7 @@ bool LambdaExpr::isMutable() const {
10441044
ExprWithCleanups::ExprWithCleanups(Expr *subexpr,
10451045
bool CleanupsHaveSideEffects,
10461046
ArrayRef<CleanupObject> objects)
1047-
: Expr(ExprWithCleanupsClass, subexpr->getType(),
1048-
subexpr->getValueKind(), subexpr->getObjectKind(),
1049-
subexpr->isTypeDependent(), subexpr->isValueDependent(),
1050-
subexpr->isInstantiationDependent(),
1051-
subexpr->containsUnexpandedParameterPack()),
1052-
SubExpr(subexpr) {
1047+
: FullExpr(ExprWithCleanupsClass, subexpr) {
10531048
ExprWithCleanupsBits.CleanupsHaveSideEffects = CleanupsHaveSideEffects;
10541049
ExprWithCleanupsBits.NumObjects = objects.size();
10551050
for (unsigned i = 0, e = objects.size(); i != e; ++i)
@@ -1066,7 +1061,7 @@ ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, Expr *subexpr,
10661061
}
10671062

10681063
ExprWithCleanups::ExprWithCleanups(EmptyShell empty, unsigned numObjects)
1069-
: Expr(ExprWithCleanupsClass, empty) {
1064+
: FullExpr(ExprWithCleanupsClass, empty) {
10701065
ExprWithCleanupsBits.NumObjects = numObjects;
10711066
}
10721067

clang/lib/AST/ExprClassification.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
194194
case Expr::DesignatedInitUpdateExprClass:
195195
return Cl::CL_PRValue;
196196

197+
case Expr::ConstantExprClass:
198+
return ClassifyInternal(Ctx, cast<ConstantExpr>(E)->getSubExpr());
199+
197200
// Next come the complicated cases.
198201
case Expr::SubstNonTypeTemplateParmExprClass:
199202
return ClassifyInternal(Ctx,

clang/lib/AST/ExprConstant.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ namespace {
143143
// If we're doing a variable assignment from e.g. malloc(N), there will
144144
// probably be a cast of some kind. In exotic cases, we might also see a
145145
// top-level ExprWithCleanups. Ignore them either way.
146-
if (const auto *EC = dyn_cast<ExprWithCleanups>(E))
147-
E = EC->getSubExpr()->IgnoreParens();
146+
if (const auto *FE = dyn_cast<FullExpr>(E))
147+
E = FE->getSubExpr()->IgnoreParens();
148148

149149
if (const auto *Cast = dyn_cast<CastExpr>(E))
150150
E = Cast->getSubExpr()->IgnoreParens();
@@ -11062,6 +11062,9 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
1106211062
return
1106311063
CheckICE(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Ctx);
1106411064

11065+
case Expr::ConstantExprClass:
11066+
return CheckICE(cast<ConstantExpr>(E)->getSubExpr(), Ctx);
11067+
1106511068
case Expr::ParenExprClass:
1106611069
return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx);
1106711070
case Expr::GenericSelectionExprClass:

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3507,6 +3507,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
35073507
case Expr::CXXInheritedCtorInitExprClass:
35083508
llvm_unreachable("unexpected statement kind");
35093509

3510+
case Expr::ConstantExprClass:
3511+
E = cast<ConstantExpr>(E)->getSubExpr();
3512+
goto recurse;
3513+
35103514
// FIXME: invent manglings for all these.
35113515
case Expr::BlockExprClass:
35123516
case Expr::ChooseExprClass:

clang/lib/AST/ParentMap.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ bool ParentMap::isConsumedExpr(Expr* E) const {
163163

164164
// Ignore parents that don't guarantee consumption.
165165
while (P && (isa<ParenExpr>(P) || isa<CastExpr>(P) ||
166-
isa<ExprWithCleanups>(P))) {
166+
isa<FullExpr>(P))) {
167167
DirectChild = P;
168168
P = getParent(P);
169169
}

clang/lib/AST/Stmt.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ Stmt *Stmt::IgnoreImplicit() {
118118
while (s != lasts) {
119119
lasts = s;
120120

121-
if (auto *ewc = dyn_cast<ExprWithCleanups>(s))
122-
s = ewc->getSubExpr();
121+
if (auto *fe = dyn_cast<FullExpr>(s))
122+
s = fe->getSubExpr();
123123

124124
if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s))
125125
s = mte->GetTemporaryExpr();

clang/lib/AST/StmtPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,10 @@ void StmtPrinter::VisitOMPTargetTeamsDistributeSimdDirective(
906906
// Expr printing methods.
907907
//===----------------------------------------------------------------------===//
908908

909+
void StmtPrinter::VisitConstantExpr(ConstantExpr *Node) {
910+
PrintExpr(Node->getSubExpr());
911+
}
912+
909913
void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
910914
if (const auto *OCED = dyn_cast<OMPCapturedExprDecl>(Node->getDecl())) {
911915
OCED->getInit()->IgnoreImpCasts()->printPretty(OS, nullptr, Policy);

clang/lib/AST/StmtProfile.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,10 @@ void StmtProfiler::VisitExpr(const Expr *S) {
996996
VisitStmt(S);
997997
}
998998

999+
void StmtProfiler::VisitConstantExpr(const ConstantExpr *S) {
1000+
VisitExpr(S);
1001+
}
1002+
9991003
void StmtProfiler::VisitDeclRefExpr(const DeclRefExpr *S) {
10001004
VisitExpr(S);
10011005
if (!Canonical)

clang/lib/Analysis/LiveVariables.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,8 @@ static const Stmt *LookThroughStmt(const Stmt *S) {
237237
while (S) {
238238
if (const Expr *Ex = dyn_cast<Expr>(S))
239239
S = Ex->IgnoreParens();
240-
if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S)) {
241-
S = EWC->getSubExpr();
240+
if (const FullExpr *FE = dyn_cast<FullExpr>(S)) {
241+
S = FE->getSubExpr();
242242
continue;
243243
}
244244
if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) {

clang/lib/Analysis/ThreadSafety.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,8 +1398,8 @@ const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(const Stmt *Cond,
13981398
return getTrylockCallExpr(PE->getSubExpr(), C, Negate);
13991399
else if (const auto *CE = dyn_cast<ImplicitCastExpr>(Cond))
14001400
return getTrylockCallExpr(CE->getSubExpr(), C, Negate);
1401-
else if (const auto *EWC = dyn_cast<ExprWithCleanups>(Cond))
1402-
return getTrylockCallExpr(EWC->getSubExpr(), C, Negate);
1401+
else if (const auto *FE = dyn_cast<FullExpr>(Cond))
1402+
return getTrylockCallExpr(FE->getSubExpr(), C, Negate);
14031403
else if (const auto *DRE = dyn_cast<DeclRefExpr>(Cond)) {
14041404
const Expr *E = LocalVarMap.lookupExpr(DRE->getDecl(), C);
14051405
return getTrylockCallExpr(E, C, Negate);

clang/lib/Analysis/ThreadSafetyCommon.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
235235
cast<BinaryConditionalOperator>(S), Ctx);
236236

237237
// We treat these as no-ops
238+
case Stmt::ConstantExprClass:
239+
return translate(cast<ConstantExpr>(S)->getSubExpr(), Ctx);
238240
case Stmt::ParenExprClass:
239241
return translate(cast<ParenExpr>(S)->getSubExpr(), Ctx);
240242
case Stmt::ExprWithCleanupsClass:

clang/lib/CodeGen/CGBlocks.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -859,10 +859,12 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) {
859859
/// Enter a full-expression with a non-trivial number of objects to
860860
/// clean up. This is in this file because, at the moment, the only
861861
/// kind of cleanup object is a BlockDecl*.
862-
void CodeGenFunction::enterNonTrivialFullExpression(const ExprWithCleanups *E) {
863-
assert(E->getNumObjects() != 0);
864-
for (const ExprWithCleanups::CleanupObject &C : E->getObjects())
865-
enterBlockScope(*this, C);
862+
void CodeGenFunction::enterNonTrivialFullExpression(const FullExpr *E) {
863+
if (const auto EWC = dyn_cast<ExprWithCleanups>(E)) {
864+
assert(EWC->getNumObjects() != 0);
865+
for (const ExprWithCleanups::CleanupObject &C : EWC->getObjects())
866+
enterBlockScope(*this, C);
867+
}
866868
}
867869

868870
/// Find the layout for the given block in a linked list and remove it.

clang/lib/CodeGen/CGDecl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -754,9 +754,9 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
754754

755755
// If we're emitting a value with lifetime, we have to do the
756756
// initialization *before* we leave the cleanup scopes.
757-
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(init)) {
758-
enterFullExpression(ewc);
759-
init = ewc->getSubExpr();
757+
if (const FullExpr *fe = dyn_cast<FullExpr>(init)) {
758+
enterFullExpression(fe);
759+
init = fe->getSubExpr();
760760
}
761761
CodeGenFunction::RunCleanupsScope Scope(*this);
762762

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,10 +1047,9 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
10471047
// exception to our over-conservative rules about not jumping to
10481048
// statements following block literals with non-trivial cleanups.
10491049
RunCleanupsScope cleanupScope(*this);
1050-
if (const ExprWithCleanups *cleanups =
1051-
dyn_cast_or_null<ExprWithCleanups>(RV)) {
1052-
enterFullExpression(cleanups);
1053-
RV = cleanups->getSubExpr();
1050+
if (const FullExpr *fe = dyn_cast_or_null<FullExpr>(RV)) {
1051+
enterFullExpression(fe);
1052+
RV = fe->getSubExpr();
10541053
}
10551054

10561055
// FIXME: Clean this up by using an LValue for ReturnTemp,

0 commit comments

Comments
 (0)