Add initial switch stmt support, patch by Anders Carlsson!

llvm-svn: 39989
This commit is contained in:
Chris Lattner 2007-07-18 02:28:47 +00:00
parent a603a80607
commit 46eeb22fec
7 changed files with 59 additions and 12 deletions

View 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);
}

View 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,

View 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();
}

View 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);

View 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")

View 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;
}

View 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;