diff --git a/clang/Sema/SemaStmt.cpp b/clang/Sema/SemaStmt.cpp index 395948c062ef..17e042c9f103 100644 --- a/clang/Sema/SemaStmt.cpp +++ b/clang/Sema/SemaStmt.cpp @@ -52,55 +52,63 @@ Sema::ParseCompoundStmt(SourceLocation L, SourceLocation R, Action::StmtResult Sema::ParseCaseStmt(SourceLocation CaseLoc, ExprTy *lhsval, SourceLocation DotDotDotLoc, ExprTy *rhsval, - SourceLocation ColonLoc, StmtTy *SubStmt) { + SourceLocation ColonLoc, StmtTy *subStmt) { + Stmt *SubStmt = static_cast(subStmt); Expr *LHSVal = ((Expr *)lhsval); assert((LHSVal != 0) && "missing expression in case statement"); SourceLocation ExpLoc; // C99 6.8.4.2p3: The expression shall be an integer constant. - if (!LHSVal->isIntegerConstantExpr(Context, &ExpLoc)) - return Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr, - LHSVal->getSourceRange()); + if (!LHSVal->isIntegerConstantExpr(Context, &ExpLoc)) { + Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr, + LHSVal->getSourceRange()); + return SubStmt; + } // GCC extension: The expression shall be an integer constant. Expr *RHSVal = ((Expr *)rhsval); - if (RHSVal) { - if (!RHSVal->isIntegerConstantExpr(Context, &ExpLoc)) - return Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr, - RHSVal->getSourceRange()); + if (RHSVal && !RHSVal->isIntegerConstantExpr(Context, &ExpLoc)) { + Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr, + RHSVal->getSourceRange()); + return SubStmt; } - return new CaseStmt(LHSVal, (Expr*)RHSVal, (Stmt*)SubStmt); + return new CaseStmt(LHSVal, (Expr*)RHSVal, SubStmt); } Action::StmtResult Sema::ParseDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, - StmtTy *SubStmt, Scope *CurScope) { + StmtTy *subStmt, Scope *CurScope) { + Stmt *SubStmt = static_cast(subStmt); Scope *S = CurScope->getBreakParent(); + if (!S) { + Diag(DefaultLoc, diag::err_default_not_in_switch); + return SubStmt; + } + if (S->getDefaultStmt()) { Diag(DefaultLoc, diag::err_multiple_default_labels_defined); Diag(((DefaultStmt *)S->getDefaultStmt())->getDefaultLoc(), diag::err_first_label); - - return true; + return SubStmt; } - DefaultStmt *DS = new DefaultStmt(DefaultLoc, (Stmt*)SubStmt); + DefaultStmt *DS = new DefaultStmt(DefaultLoc, SubStmt); S->setDefaultStmt(DS); - return DS; } Action::StmtResult Sema::ParseLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, - SourceLocation ColonLoc, StmtTy *SubStmt) { + SourceLocation ColonLoc, StmtTy *subStmt) { + Stmt *SubStmt = static_cast(subStmt); // Look up the record for this label identifier. LabelStmt *&LabelDecl = LabelMap[II]; // If not forward referenced or defined already, just create a new LabelStmt. if (LabelDecl == 0) - return LabelDecl = new LabelStmt(IdentLoc, II, (Stmt*)SubStmt); + return LabelDecl = new LabelStmt(IdentLoc, II, SubStmt); assert(LabelDecl->getID() == II && "Label mismatch!"); @@ -109,13 +117,13 @@ Sema::ParseLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, if (LabelDecl->getSubStmt()) { Diag(IdentLoc, diag::err_redefinition_of_label, LabelDecl->getName()); Diag(LabelDecl->getIdentLoc(), diag::err_previous_definition); - return (Stmt*)SubStmt; + return SubStmt; } // Otherwise, this label was forward declared, and we just found its real // definition. Fill in the forward definition and return it. LabelDecl->setIdentLoc(IdentLoc); - LabelDecl->setSubStmt((Stmt*)SubStmt); + LabelDecl->setSubStmt(SubStmt); return LabelDecl; } diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 5459e35c89b1..6a3ecf7814cb 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -653,6 +653,8 @@ DIAG(err_continue_not_in_loop, ERROR, "'continue' statement not in loop statement") DIAG(err_break_not_in_loop_or_switch, ERROR, "'break' statement not in loop or switch statement") +DIAG(err_default_not_in_switch, ERROR, + "'default' statement not in switch statement") DIAG(err_typecheck_return_incompatible, ERROR, "incompatible type returning '%1', expected '%0'") DIAG(ext_typecheck_return_pointer_int, EXTENSION, diff --git a/clang/test/Sema/default.c b/clang/test/Sema/default.c new file mode 100644 index 000000000000..e714effde2c5 --- /dev/null +++ b/clang/test/Sema/default.c @@ -0,0 +1,8 @@ +// RUN: clang -parse-ast-check %s + +void f5 (int z) { + if (z) + default: // expected-error {{not in switch statement}} + ; +} +