Index: clang/lib/AST/Interp/ByteCodeExprGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -179,6 +179,9 @@ return this->emitPopPtr(I); } + template + bool visitConditional(const AbstractConditionalOperator *E, VisitFn V); + /// Creates a local primitive value. unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable, bool IsExtended = false); Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -588,32 +588,8 @@ template bool ByteCodeExprGen::VisitAbstractConditionalOperator( const AbstractConditionalOperator *E) { - const Expr *Condition = E->getCond(); - const Expr *TrueExpr = E->getTrueExpr(); - const Expr *FalseExpr = E->getFalseExpr(); - - LabelTy LabelEnd = this->getLabel(); // Label after the operator. - LabelTy LabelFalse = this->getLabel(); // Label for the false expr. - - if (!this->visit(Condition)) - return false; - if (!this->jumpFalse(LabelFalse)) - return false; - - if (!this->visit(TrueExpr)) - return false; - if (!this->jump(LabelEnd)) - return false; - - this->emitLabel(LabelFalse); - - if (!this->visit(FalseExpr)) - return false; - - this->fallthrough(LabelEnd); - this->emitLabel(LabelEnd); - - return true; + return this->visitConditional( + E, [this](const Expr *E) { return this->visit(E); }); } template @@ -944,6 +920,41 @@ } } +/// Visit a conditional operator, i.e. `A ? B : C`. +/// \V determines what function to call for the B and C expressions. +template +template +bool ByteCodeExprGen::visitConditional( + const AbstractConditionalOperator *E, VisitFn V) { + + const Expr *Condition = E->getCond(); + const Expr *TrueExpr = E->getTrueExpr(); + const Expr *FalseExpr = E->getFalseExpr(); + + LabelTy LabelEnd = this->getLabel(); // Label after the operator. + LabelTy LabelFalse = this->getLabel(); // Label for the false expr. + + if (!this->visit(Condition)) + return false; + if (!this->jumpFalse(LabelFalse)) + return false; + + if (!V(TrueExpr)) + return false; + if (!this->jump(LabelEnd)) + return false; + + this->emitLabel(LabelFalse); + + if (!V(FalseExpr)) + return false; + + this->fallthrough(LabelEnd); + this->emitLabel(LabelEnd); + + return true; +} + template bool ByteCodeExprGen::visitZeroInitializer(PrimType T, const Expr *E) { switch (T) { @@ -1435,6 +1446,10 @@ return this->visitInitializer(CE->getSubExpr()); } else if (const auto *CE = dyn_cast(Initializer)) { return this->visitInitializer(CE->getSubExpr()); + } else if (const auto *ACO = + dyn_cast(Initializer)) { + return this->visitConditional( + ACO, [this](const Expr *E) { return this->visitRecordInitializer(E); }); } return false; Index: clang/test/AST/Interp/records.cpp =================================================================== --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -335,3 +335,14 @@ constexpr piecewise_construct_t piecewise_construct = piecewise_construct_t(); }; + +namespace ConditionalInit { + struct S { int a; }; + + constexpr S getS(bool b) { + return b ? S{12} : S{13}; + } + + static_assert(getS(true).a == 12, ""); + static_assert(getS(false).a == 13, ""); +};