Skip to content

Commit c49c386

Browse files
committed
[clang][Interp] Reject StmtExprs containing return statements
1 parent 17bd312 commit c49c386

File tree

5 files changed

+39
-0
lines changed

5 files changed

+39
-0
lines changed

clang/lib/AST/Interp/Compiler.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,19 @@ template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
154154
CaseMap OldCaseLabels;
155155
};
156156

157+
template <class Emitter> class StmtExprScope final {
158+
public:
159+
StmtExprScope(Compiler<Emitter> *Ctx) : Ctx(Ctx), OldFlag(Ctx->InStmtExpr) {
160+
Ctx->InStmtExpr = true;
161+
}
162+
163+
~StmtExprScope() { Ctx->InStmtExpr = OldFlag; }
164+
165+
private:
166+
Compiler<Emitter> *Ctx;
167+
bool OldFlag;
168+
};
169+
157170
} // namespace interp
158171
} // namespace clang
159172

@@ -3028,6 +3041,7 @@ bool Compiler<Emitter>::VisitCXXStdInitializerListExpr(
30283041
template <class Emitter>
30293042
bool Compiler<Emitter>::VisitStmtExpr(const StmtExpr *E) {
30303043
BlockScope<Emitter> BS(this);
3044+
StmtExprScope<Emitter> SS(this);
30313045

30323046
const CompoundStmt *CS = E->getSubStmt();
30333047
const Stmt *Result = CS->getStmtExprResult();
@@ -4056,6 +4070,9 @@ bool Compiler<Emitter>::visitDeclStmt(const DeclStmt *DS) {
40564070

40574071
template <class Emitter>
40584072
bool Compiler<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
4073+
if (this->InStmtExpr)
4074+
return this->emitUnsupported(RS);
4075+
40594076
if (const Expr *RE = RS->getRetValue()) {
40604077
ExprScope<Emitter> RetScope(this);
40614078
if (ReturnType) {

clang/lib/AST/Interp/Compiler.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ template <class Emitter> class SourceLocScope;
3939
template <class Emitter> class LoopScope;
4040
template <class Emitter> class LabelScope;
4141
template <class Emitter> class SwitchScope;
42+
template <class Emitter> class StmtExprScope;
4243

4344
template <class Emitter> class Compiler;
4445
struct InitLink {
@@ -334,6 +335,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
334335
friend class LoopScope<Emitter>;
335336
friend class LabelScope<Emitter>;
336337
friend class SwitchScope<Emitter>;
338+
friend class StmtExprScope<Emitter>;
337339

338340
/// Emits a zero initializer.
339341
bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
@@ -398,6 +400,8 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
398400
/// Flag indicating if return value is to be discarded.
399401
bool DiscardResult = false;
400402

403+
bool InStmtExpr = false;
404+
401405
/// Flag inidicating if we're initializing an already created
402406
/// variable. This is set in visitInitializer().
403407
bool Initializing = false;

clang/lib/AST/Interp/Interp.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2618,6 +2618,13 @@ inline bool Invalid(InterpState &S, CodePtr OpPC) {
26182618
return false;
26192619
}
26202620

2621+
inline bool Unsupported(InterpState &S, CodePtr OpPC) {
2622+
const SourceLocation &Loc = S.Current->getLocation(OpPC);
2623+
S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
2624+
<< S.Current->getRange(OpPC);
2625+
return false;
2626+
}
2627+
26212628
/// Do nothing and just abort execution.
26222629
inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
26232630

clang/lib/AST/Interp/Opcodes.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,7 @@ def Dup : Opcode {
714714

715715
// [] -> []
716716
def Invalid : Opcode {}
717+
def Unsupported : Opcode {}
717718
def Error : Opcode {}
718719
def InvalidCast : Opcode {
719720
let Args = [ArgCastKind];

clang/test/AST/Interp/literals.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,4 +1255,14 @@ constexpr int StmtExprEval() {
12551255
return 1;
12561256
}
12571257
static_assert(StmtExprEval() == 2, "");
1258+
1259+
constexpr int ReturnInStmtExpr() { // both-error {{never produces a constant expression}}
1260+
return ({
1261+
return 1; // both-note 2{{this use of statement expressions is not supported in a constant expression}}
1262+
2;
1263+
});
1264+
}
1265+
static_assert(ReturnInStmtExpr() == 1, ""); // both-error {{not an integral constant expression}} \
1266+
// both-note {{in call to}}
1267+
12581268
#endif

0 commit comments

Comments
 (0)