]> granicus.if.org Git - clang/commitdiff
Add initial switch stmt support, patch by Anders Carlsson!
authorChris Lattner <sabre@nondot.org>
Wed, 18 Jul 2007 02:28:47 +0000 (02:28 +0000)
committerChris Lattner <sabre@nondot.org>
Wed, 18 Jul 2007 02:28:47 +0000 (02:28 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@39989 91177308-0d34-0410-b5e6-96231b3b80d8

Parse/ParseStmt.cpp
Sema/Sema.h
Sema/SemaStmt.cpp
include/clang/AST/Stmt.h
include/clang/Basic/DiagnosticKinds.def
include/clang/Parse/Action.h
include/clang/Parse/Scope.h

index 7bc7a9c9a76b03b9975b4a815768cc48587e445e..7a841e23cef9e3f23449cc5be79c1e2846eba5d3 100644 (file)
@@ -338,7 +338,7 @@ Parser::StmtResult Parser::ParseDefaultStatement() {
     return true;
   
   // TODO: look up enclosing switch stmt.
-  return Actions.ParseDefaultStmt(DefaultLoc, ColonLoc, SubStmt.Val);
+  return Actions.ParseDefaultStmt(DefaultLoc, ColonLoc, SubStmt.Val, CurScope);
 }
 
 
index 76da577fa43dd605febb30eb5d0394af925f1bdd..e386001214d3cb6894e8f04904ca902ddb5b78cb 100644 (file)
@@ -167,7 +167,8 @@ public:
                                    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 df240a814bb5749786ab5e8d6e54a50b6f8c2190..395948c062ef7198e7359d0a7ee5970e469019fe 100644 (file)
@@ -51,7 +51,7 @@ Sema::ParseCompoundStmt(SourceLocation L, SourceLocation R,
 
 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 @@ Sema::ParseCaseStmt(SourceLocation CaseLoc, ExprTy *lhsval,
     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 @@ Sema::ParseIfStmt(SourceLocation IfLoc, ExprTy *CondVal,
 
 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 @@ Sema::ParseContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
     return true;
   }
   
-  // FIXME: Remember that this continue goes with this loop.
   return new ContinueStmt();
 }
 
@@ -218,7 +244,6 @@ Sema::ParseBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
     return true;
   }
   
-  // FIXME: Remember that this break goes with this loop/switch.
   return new BreakStmt();
 }
 
index f3fb9079357c3c2670129a0832641e652544feb2..3de6268cfdbc383040618e8b76a50157cb7700d9 100644 (file)
@@ -23,6 +23,7 @@ namespace clang {
   class Decl;
   class IdentifierInfo;
   class StmtVisitor;
+  class SwitchStmt;
   
 /// Stmt - This represents one statement.
 ///
@@ -127,9 +128,11 @@ class CaseStmt : public Stmt {
   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 @@ public:
 };
 
 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 721176147cf34d8b52482755fb655e8d44c40361..7486883b3159162fbe7a086207066f811d383e1b 100644 (file)
@@ -464,6 +464,8 @@ DIAG(err_previous_definition, ERROR,
      "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 @@ DIAG(ext_typecheck_return_discards_qualifiers, EXTENSION,
      "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 bd7fbe4e5e7c73af3d63e99abe4b655be7288f0a..bf5499a081076e637bfc6adcf402101c0eb137cd 100644 (file)
@@ -204,7 +204,8 @@ public:
     return 0;
   }
   virtual StmtResult ParseDefaultStmt(SourceLocation DefaultLoc,
-                                      SourceLocation ColonLoc, StmtTy *SubStmt){
+                                      SourceLocation ColonLoc, StmtTy *SubStmt,
+                                      Scope *CurScope){
     return 0;
   }
   
index 367bbf2523121057c4bd78542cdda7bd3f6b11e0..b02f082934cb631766d15307ebfc8e1d77ec56c9 100644 (file)
@@ -78,6 +78,10 @@ private:
   /// implement these semantics.
   typedef llvm::SmallPtrSet<Action::DeclTy*, 32> 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 @@ public:
     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 @@ public:
       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;