class SwitchStmt : public Stmt {
enum { COND, BODY, END_EXPR };
Stmt* SubExprs[END_EXPR];
+ VarDecl *Var;
// This points to a linked list of case and default statements.
SwitchCase *FirstCase;
SourceLocation SwitchLoc;
virtual void DoDestroy(ASTContext &Ctx);
public:
- SwitchStmt(Expr *cond) : Stmt(SwitchStmtClass), FirstCase(0) {
- SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
- SubExprs[BODY] = NULL;
- }
+ SwitchStmt(VarDecl *Var, Expr *cond)
+ : Stmt(SwitchStmtClass), Var(Var), FirstCase(0)
+ {
+ SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
+ SubExprs[BODY] = NULL;
+ }
/// \brief Build a empty switch statement.
explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { }
+ /// \brief Retrieve the variable declared in this "switch" statement, if any.
+ ///
+ /// In the following example, "x" is the condition variable.
+ /// \code
+ /// switch (int x = foo()) {
+ /// case 0: break;
+ /// // ...
+ /// }
+ /// \endcode
+ VarDecl *getConditionVariable() const { return Var; }
+ void setConditionVariable(VarDecl *V) { Var = V; }
+
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
const Stmt *getBody() const { return SubExprs[BODY]; }
const SwitchCase *getSwitchCaseList() const { return FirstCase; }
}
void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
+ CleanupScope ConditionScope(*this);
+
+ if (S.getConditionVariable())
+ EmitLocalBlockVarDecl(*S.getConditionVariable());
+
llvm::Value *CondV = EmitScalarExpr(S.getCond());
// Handle nested switch statements.
unsigned PCHStmtReader::VisitSwitchStmt(SwitchStmt *S) {
VisitStmt(S);
+ S->setConditionVariable(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 2]));
S->setBody(StmtStack.back());
S->setSwitchLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
VisitStmt(S);
+ Writer.AddDeclRef(S->getConditionVariable(), Record);
Writer.WriteSubStmt(S->getCond());
Writer.WriteSubStmt(S->getBody());
Writer.AddSourceLocation(S->getSwitchLoc(), Record);
Action::OwningStmtResult
Sema::ActOnStartOfSwitchStmt(ExprArg cond) {
- SwitchStmt *SS = new (Context) SwitchStmt(cond.takeAs<Expr>());
+ Expr *condExpr = cond.takeAs<Expr>();
+ VarDecl *ConditionVar = 0;
+ if (CXXConditionDeclExpr *Cond = dyn_cast<CXXConditionDeclExpr>(condExpr)) {
+ ConditionVar = Cond->getVarDecl();
+ condExpr = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar,
+ ConditionVar->getLocation(),
+ ConditionVar->getType().getNonReferenceType());
+ // FIXME: Leaks the old condExpr
+ }
+
+ SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar, condExpr);
getSwitchStack().push_back(SS);
return Owned(SS);
}
Sema::OwningStmtResult
TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
// Transform the condition.
- OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+ OwningExprResult Cond(SemaRef);
+ VarDecl *ConditionVar = 0;
+ if (S->getConditionVariable()) {
+ ConditionVar
+ = cast_or_null<VarDecl>(
+ getDerived().TransformDefinition(S->getConditionVariable()));
+ if (!ConditionVar)
+ return SemaRef.StmtError();
+
+ Cond = getSema().CheckConditionVariable(ConditionVar);
+ } else
+ Cond = getDerived().TransformExpr(S->getCond());
if (Cond.isInvalid())
return SemaRef.StmtError();
// CHECK: if.end
// CHECK: call void @_ZN1XD1Ev
}
+
+struct ConvertibleToInt {
+ ConvertibleToInt();
+ ~ConvertibleToInt();
+ operator int();
+};
+
+void switch_destruct(int z) {
+ // CHECK: call void @_ZN16ConvertibleToIntC1Ev
+ switch (ConvertibleToInt conv = ConvertibleToInt()) {
+ case 0:
+ break;
+
+ default:
+ // CHECK: sw.default:
+ // CHECK: store i32 19
+ z = 19;
+ break;
+ }
+ // CHECK: sw.epilog:
+ // CHECK: call void @_ZN16ConvertibleToIntD1Ev
+ // CHECK: store i32 20
+ z = 20;
+}