Index: include/clang/Basic/DiagnosticKinds.def =================================================================== --- include/clang/Basic/DiagnosticKinds.def (revision 39986) +++ include/clang/Basic/DiagnosticKinds.def (arbetskopia) @@ -464,6 +464,8 @@ "previous definition is here") DIAG(err_previous_use, ERROR, "previous use is here") +DIAG(err_first_label, ERROR, + "first label is here") DIAG(err_unexpected_typedef, ERROR, "unexpected type name '%0': expected expression") @@ -659,6 +661,10 @@ "returning '%1' from function expecting '%0' discards qualifiers") DIAG(err_typecheck_statement_requires_scalar, ERROR, "statement requires expression of scalar type ('%0' invalid)") +DIAG(err_typecheck_statement_requires_integer, ERROR, + "statement requires expression of integer type ('%0' invalid)") +DIAG(err_multiple_default_labels_defined, ERROR, + "multiple default labels in one switch") DIAG(warn_return_missing_expr, WARNING, "non-void function '%0' should return a value") Index: include/clang/AST/Stmt.h =================================================================== --- include/clang/AST/Stmt.h (revision 39986) +++ include/clang/AST/Stmt.h (arbetskopia) @@ -23,6 +23,7 @@ class Decl; class IdentifierInfo; class StmtVisitor; + class SwitchStmt; /// Stmt - This represents one statement. /// @@ -127,9 +128,11 @@ Expr *LHSVal; Expr *RHSVal; // Non-null for GNU "case 1 ... 4" extension Stmt *SubStmt; + SwitchStmt *Switch; public: CaseStmt(Expr *lhs, Expr *rhs, Stmt *substmt) - : Stmt(CaseStmtClass), LHSVal(lhs), RHSVal(rhs), SubStmt(substmt) {} + : Stmt(CaseStmtClass), LHSVal(lhs), RHSVal(rhs), SubStmt(substmt), + Switch(0) {} Expr *getLHS() { return LHSVal; } Expr *getRHS() { return RHSVal; } @@ -143,10 +146,13 @@ }; class DefaultStmt : public Stmt { + SourceLocation DefaultLoc; Stmt *SubStmt; public: - DefaultStmt(Stmt *substmt) : Stmt(DefaultStmtClass), SubStmt(substmt) {} + DefaultStmt(SourceLocation DL, Stmt *substmt) : Stmt(DefaultStmtClass), + DefaultLoc(DL), SubStmt(substmt) {} + SourceLocation getDefaultLoc() const { return DefaultLoc; } Stmt *getSubStmt() { return SubStmt; } virtual void visit(StmtVisitor &Visitor); Index: include/clang/Parse/Scope.h =================================================================== --- include/clang/Parse/Scope.h (revision 39986) +++ include/clang/Parse/Scope.h (arbetskopia) @@ -78,6 +78,10 @@ /// implement these semantics. typedef llvm::SmallPtrSet DeclSetTy; DeclSetTy DeclsInScope; + + /// DefaultStmt - when parsing the body of a switch statement, this keeps + /// track of the statement with the default label. + Action::StmtTy *DefaultStmt; public: Scope(Scope *Parent, unsigned ScopeFlags) { Init(Parent, ScopeFlags); @@ -114,6 +118,8 @@ return DeclsInScope.count(D) != 0; } + void setDefaultStmt(Action::StmtTy *S) { DefaultStmt = S; } + Action::StmtTy *getDefaultStmt() const { return DefaultStmt; } /// Init - This is used by the parser to implement scope caching. /// @@ -132,6 +138,8 @@ FnParent = BreakParent = ContinueParent = 0; } + DefaultStmt = 0; + // If this scope is a function or contains breaks/continues, remember it. if (Flags & FnScope) FnParent = this; if (Flags & BreakScope) BreakParent = this; Index: include/clang/Parse/Action.h =================================================================== --- include/clang/Parse/Action.h (revision 39986) +++ include/clang/Parse/Action.h (arbetskopia) @@ -204,7 +204,8 @@ return 0; } virtual StmtResult ParseDefaultStmt(SourceLocation DefaultLoc, - SourceLocation ColonLoc, StmtTy *SubStmt){ + SourceLocation ColonLoc, StmtTy *SubStmt, + Scope *CurScope){ return 0; } Index: Sema/Sema.h =================================================================== --- Sema/Sema.h (revision 39986) +++ Sema/Sema.h (arbetskopia) @@ -167,7 +167,8 @@ SourceLocation DotDotDotLoc, ExprTy *RHSVal, SourceLocation ColonLoc, StmtTy *SubStmt); virtual StmtResult ParseDefaultStmt(SourceLocation DefaultLoc, - SourceLocation ColonLoc, StmtTy *SubStmt); + SourceLocation ColonLoc, StmtTy *SubStmt, + Scope *CurScope); virtual StmtResult ParseLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, SourceLocation ColonLoc, StmtTy *SubStmt); virtual StmtResult ParseIfStmt(SourceLocation IfLoc, ExprTy *CondVal, Index: Sema/SemaStmt.cpp =================================================================== --- Sema/SemaStmt.cpp (revision 39986) +++ Sema/SemaStmt.cpp (arbetskopia) @@ -51,7 +51,7 @@ Action::StmtResult Sema::ParseCaseStmt(SourceLocation CaseLoc, ExprTy *lhsval, - SourceLocation DotDotDotLoc, ExprTy *RHSVal, + SourceLocation DotDotDotLoc, ExprTy *rhsval, SourceLocation ColonLoc, StmtTy *SubStmt) { Expr *LHSVal = ((Expr *)lhsval); assert((LHSVal != 0) && "missing expression in case statement"); @@ -62,15 +62,34 @@ return Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr, LHSVal->getSourceRange()); - // FIXME: SEMA for RHS of case range. + // 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()); + } return new CaseStmt(LHSVal, (Expr*)RHSVal, (Stmt*)SubStmt); } Action::StmtResult -Sema::ParseDefaultStmt(SourceLocation DefaultLoc, - SourceLocation ColonLoc, StmtTy *SubStmt) { - return new DefaultStmt((Stmt*)SubStmt); +Sema::ParseDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, + StmtTy *SubStmt, Scope *CurScope) { + Scope *S = CurScope->getBreakParent(); + + if (S->getDefaultStmt()) { + Diag(DefaultLoc, diag::err_multiple_default_labels_defined); + Diag(((DefaultStmt *)S->getDefaultStmt())->getDefaultLoc(), + diag::err_first_label); + + return true; + } + + DefaultStmt *DS = new DefaultStmt(DefaultLoc, (Stmt*)SubStmt); + S->setDefaultStmt(DS); + + return DS; } Action::StmtResult @@ -119,6 +138,14 @@ Action::StmtResult Sema::ParseSwitchStmt(SourceLocation SwitchLoc, ExprTy *Cond, StmtTy *Body) { + Expr *condExpr = (Expr *)Cond; + + QualType condType = condExpr->getType(); + + if (!condType->isIntegerType()) // C99 6.8.4.2p1 + return Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer, + condType.getAsString(), condExpr->getSourceRange()); + return new SwitchStmt((Expr*)Cond, (Stmt*)Body); } @@ -205,7 +232,6 @@ return true; } - // FIXME: Remember that this continue goes with this loop. return new ContinueStmt(); } @@ -218,7 +244,6 @@ return true; } - // FIXME: Remember that this break goes with this loop/switch. return new BreakStmt(); } Index: Parse/ParseStmt.cpp =================================================================== --- Parse/ParseStmt.cpp (revision 39986) +++ Parse/ParseStmt.cpp (arbetskopia) @@ -338,7 +338,7 @@ return true; // TODO: look up enclosing switch stmt. - return Actions.ParseDefaultStmt(DefaultLoc, ColonLoc, SubStmt.Val); + return Actions.ParseDefaultStmt(DefaultLoc, ColonLoc, SubStmt.Val, CurScope); }