зеркало из https://github.com/microsoft/clang-1.git
366 строки
12 KiB
C++
366 строки
12 KiB
C++
//===--- SemaStmt.cpp - Semantic Analysis for Statements ------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file was developed by Chris Lattner and is distributed under
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements semantic analysis for statements.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Sema.h"
|
|
#include "clang/AST/Stmt.h"
|
|
#include "clang/AST/Expr.h"
|
|
#include "clang/Parse/Scope.h"
|
|
#include "clang/Basic/Diagnostic.h"
|
|
#include "clang/Basic/LangOptions.h"
|
|
#include "clang/Lex/IdentifierTable.h"
|
|
|
|
using namespace clang;
|
|
|
|
Sema::StmtResult Sema::ParseExprStmt(ExprTy *expr) {
|
|
Expr *E = static_cast<Expr*>(expr);
|
|
assert(E && "ParseExprStmt(): missing expression");
|
|
|
|
// Exprs are statements, so there is no need to do a conversion here. However,
|
|
// diagnose some potentially bad code.
|
|
if (!E->hasLocalSideEffect())
|
|
Diag(E->getExprLoc(), diag::warn_unused_expr, E->getSourceRange());
|
|
|
|
return E;
|
|
}
|
|
|
|
|
|
Sema::StmtResult Sema::ParseNullStmt(SourceLocation SemiLoc) {
|
|
return new NullStmt(SemiLoc);
|
|
}
|
|
|
|
Sema::StmtResult Sema::ParseDeclStmt(DeclTy *decl) {
|
|
if (decl)
|
|
return new DeclStmt(static_cast<Decl *>(decl));
|
|
else
|
|
return true; // error
|
|
}
|
|
|
|
Action::StmtResult
|
|
Sema::ParseCompoundStmt(SourceLocation L, SourceLocation R,
|
|
StmtTy **Elts, unsigned NumElts) {
|
|
return new CompoundStmt((Stmt**)Elts, NumElts);
|
|
}
|
|
|
|
Action::StmtResult
|
|
Sema::ParseCaseStmt(SourceLocation CaseLoc, ExprTy *lhsval,
|
|
SourceLocation DotDotDotLoc, ExprTy *rhsval,
|
|
SourceLocation ColonLoc, StmtTy *subStmt) {
|
|
Stmt *SubStmt = static_cast<Stmt*>(subStmt);
|
|
Expr *LHSVal = ((Expr *)lhsval), *RHSVal = ((Expr *)rhsval);
|
|
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)) {
|
|
Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr,
|
|
LHSVal->getSourceRange());
|
|
return SubStmt;
|
|
}
|
|
|
|
// GCC extension: The expression shall be an integer constant.
|
|
if (RHSVal && !RHSVal->isIntegerConstantExpr(Context, &ExpLoc)) {
|
|
Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr,
|
|
RHSVal->getSourceRange());
|
|
return SubStmt;
|
|
}
|
|
|
|
if (SwitchStack.empty()) {
|
|
Diag(CaseLoc, diag::err_case_not_in_switch);
|
|
return SubStmt;
|
|
}
|
|
|
|
CaseStmt *CS = new CaseStmt(LHSVal, RHSVal, SubStmt);
|
|
SwitchStack.back()->addSwitchCase(CS);
|
|
return CS;
|
|
}
|
|
|
|
Action::StmtResult
|
|
Sema::ParseDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
|
|
StmtTy *subStmt, Scope *CurScope) {
|
|
Stmt *SubStmt = static_cast<Stmt*>(subStmt);
|
|
|
|
if (SwitchStack.empty()) {
|
|
Diag(DefaultLoc, diag::err_default_not_in_switch);
|
|
return SubStmt;
|
|
}
|
|
|
|
DefaultStmt *DS = new DefaultStmt(DefaultLoc, SubStmt);
|
|
SwitchStack.back()->addSwitchCase(DS);
|
|
|
|
return DS;
|
|
}
|
|
|
|
Action::StmtResult
|
|
Sema::ParseLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
|
|
SourceLocation ColonLoc, StmtTy *subStmt) {
|
|
Stmt *SubStmt = static_cast<Stmt*>(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, SubStmt);
|
|
|
|
assert(LabelDecl->getID() == II && "Label mismatch!");
|
|
|
|
// Otherwise, this label was either forward reference or multiply defined. If
|
|
// multiply defined, reject it now.
|
|
if (LabelDecl->getSubStmt()) {
|
|
Diag(IdentLoc, diag::err_redefinition_of_label, LabelDecl->getName());
|
|
Diag(LabelDecl->getIdentLoc(), diag::err_previous_definition);
|
|
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(SubStmt);
|
|
return LabelDecl;
|
|
}
|
|
|
|
Action::StmtResult
|
|
Sema::ParseIfStmt(SourceLocation IfLoc, ExprTy *CondVal,
|
|
StmtTy *ThenVal, SourceLocation ElseLoc,
|
|
StmtTy *ElseVal) {
|
|
Expr *condExpr = (Expr *)CondVal;
|
|
assert(condExpr && "ParseIfStmt(): missing expression");
|
|
|
|
DefaultFunctionArrayConversion(condExpr);
|
|
QualType condType = condExpr->getType();
|
|
|
|
if (!condType->isScalarType()) // C99 6.8.4.1p1
|
|
return Diag(IfLoc, diag::err_typecheck_statement_requires_scalar,
|
|
condType.getAsString(), condExpr->getSourceRange());
|
|
|
|
return new IfStmt(condExpr, (Stmt*)ThenVal, (Stmt*)ElseVal);
|
|
}
|
|
|
|
Action::StmtResult
|
|
Sema::StartSwitchStmt(ExprTy *Cond) {
|
|
SwitchStmt *SS = new SwitchStmt((Expr*)Cond);
|
|
SwitchStack.push_back(SS);
|
|
return SS;
|
|
}
|
|
|
|
Action::StmtResult
|
|
Sema::FinishSwitchStmt(SourceLocation SwitchLoc, StmtTy *Switch, ExprTy *Body) {
|
|
Stmt *BodyStmt = (Stmt*)Body;
|
|
|
|
SwitchStmt *SS = SwitchStack.back();
|
|
assert(SS == (SwitchStmt*)Switch && "switch stack missing push/pop!");
|
|
|
|
SS->setBody(BodyStmt);
|
|
SwitchStack.pop_back();
|
|
|
|
Expr *condExpr = SS->getCond();
|
|
QualType condType = condExpr->getType();
|
|
|
|
if (!condType->isIntegerType()) { // C99 6.8.4.2p1
|
|
Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer,
|
|
condType.getAsString(), condExpr->getSourceRange());
|
|
return false;
|
|
}
|
|
|
|
DefaultStmt *CurDefaultStmt = 0;
|
|
|
|
// FIXME: The list of cases is backwards and needs to be reversed.
|
|
for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
|
|
SC = SC->getNextSwitchCase()) {
|
|
if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC)) {
|
|
if (CurDefaultStmt) {
|
|
Diag(DS->getDefaultLoc(),
|
|
diag::err_multiple_default_labels_defined);
|
|
Diag(CurDefaultStmt->getDefaultLoc(),
|
|
diag::err_first_label);
|
|
|
|
// FIXME: Remove the default statement from the switch block
|
|
// so that we'll return a valid AST.
|
|
} else {
|
|
CurDefaultStmt = DS;
|
|
}
|
|
|
|
// FIXME: Check that case values are unique here.
|
|
}
|
|
}
|
|
|
|
return SS;
|
|
}
|
|
|
|
Action::StmtResult
|
|
Sema::ParseWhileStmt(SourceLocation WhileLoc, ExprTy *Cond, StmtTy *Body) {
|
|
Expr *condExpr = (Expr *)Cond;
|
|
assert(condExpr && "ParseWhileStmt(): missing expression");
|
|
|
|
DefaultFunctionArrayConversion(condExpr);
|
|
QualType condType = condExpr->getType();
|
|
|
|
if (!condType->isScalarType()) // C99 6.8.5p2
|
|
return Diag(WhileLoc, diag::err_typecheck_statement_requires_scalar,
|
|
condType.getAsString(), condExpr->getSourceRange());
|
|
|
|
return new WhileStmt(condExpr, (Stmt*)Body);
|
|
}
|
|
|
|
Action::StmtResult
|
|
Sema::ParseDoStmt(SourceLocation DoLoc, StmtTy *Body,
|
|
SourceLocation WhileLoc, ExprTy *Cond) {
|
|
Expr *condExpr = (Expr *)Cond;
|
|
assert(condExpr && "ParseDoStmt(): missing expression");
|
|
|
|
DefaultFunctionArrayConversion(condExpr);
|
|
QualType condType = condExpr->getType();
|
|
|
|
if (!condType->isScalarType()) // C99 6.8.5p2
|
|
return Diag(DoLoc, diag::err_typecheck_statement_requires_scalar,
|
|
condType.getAsString(), condExpr->getSourceRange());
|
|
|
|
return new DoStmt((Stmt*)Body, condExpr);
|
|
}
|
|
|
|
Action::StmtResult
|
|
Sema::ParseForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
|
|
StmtTy *First, ExprTy *Second, ExprTy *Third,
|
|
SourceLocation RParenLoc, StmtTy *Body) {
|
|
if (First) {
|
|
// C99 6.8.5p3: FIXME. Need to hack Parser::ParseForStatement() and
|
|
// declaration support to create a DeclStmt node. Once this is done,
|
|
// we can test for DeclStmt vs. Expr (already a sub-class of Stmt).
|
|
}
|
|
if (Second) {
|
|
Expr *testExpr = (Expr *)Second;
|
|
DefaultFunctionArrayConversion(testExpr);
|
|
QualType testType = testExpr->getType();
|
|
|
|
if (!testType->isScalarType()) // C99 6.8.5p2
|
|
return Diag(ForLoc, diag::err_typecheck_statement_requires_scalar,
|
|
testType.getAsString(), testExpr->getSourceRange());
|
|
}
|
|
return new ForStmt((Stmt*)First, (Expr*)Second, (Expr*)Third, (Stmt*)Body);
|
|
}
|
|
|
|
|
|
Action::StmtResult
|
|
Sema::ParseGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
|
|
IdentifierInfo *LabelII) {
|
|
// Look up the record for this label identifier.
|
|
LabelStmt *&LabelDecl = LabelMap[LabelII];
|
|
|
|
// If we haven't seen this label yet, create a forward reference.
|
|
if (LabelDecl == 0)
|
|
LabelDecl = new LabelStmt(LabelLoc, LabelII, 0);
|
|
|
|
return new GotoStmt(LabelDecl);
|
|
}
|
|
|
|
Action::StmtResult
|
|
Sema::ParseIndirectGotoStmt(SourceLocation GotoLoc,SourceLocation StarLoc,
|
|
ExprTy *DestExp) {
|
|
// FIXME: Verify that the operand is convertible to void*.
|
|
|
|
return new IndirectGotoStmt((Expr*)DestExp);
|
|
}
|
|
|
|
Action::StmtResult
|
|
Sema::ParseContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
|
|
Scope *S = CurScope->getContinueParent();
|
|
if (!S) {
|
|
// C99 6.8.6.2p1: A break shall appear only in or as a loop body.
|
|
Diag(ContinueLoc, diag::err_continue_not_in_loop);
|
|
return true;
|
|
}
|
|
|
|
return new ContinueStmt();
|
|
}
|
|
|
|
Action::StmtResult
|
|
Sema::ParseBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
|
|
Scope *S = CurScope->getBreakParent();
|
|
if (!S) {
|
|
// C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body.
|
|
Diag(BreakLoc, diag::err_break_not_in_loop_or_switch);
|
|
return true;
|
|
}
|
|
|
|
return new BreakStmt();
|
|
}
|
|
|
|
|
|
Action::StmtResult
|
|
Sema::ParseReturnStmt(SourceLocation ReturnLoc, ExprTy *rex) {
|
|
Expr *RetValExp = static_cast<Expr *>(rex);
|
|
QualType lhsType = CurFunctionDecl->getResultType();
|
|
|
|
if (lhsType->isVoidType()) {
|
|
if (RetValExp) // C99 6.8.6.4p1 (ext_ since GCC warns)
|
|
Diag(ReturnLoc, diag::ext_return_has_expr,
|
|
CurFunctionDecl->getIdentifier()->getName(),
|
|
RetValExp->getSourceRange());
|
|
return new ReturnStmt(RetValExp);
|
|
} else {
|
|
if (!RetValExp) {
|
|
const char *funcName = CurFunctionDecl->getIdentifier()->getName();
|
|
if (getLangOptions().C99) // C99 6.8.6.4p1 (ext_ since GCC warns)
|
|
Diag(ReturnLoc, diag::ext_return_missing_expr, funcName);
|
|
else // C90 6.6.6.4p4
|
|
Diag(ReturnLoc, diag::warn_return_missing_expr, funcName);
|
|
return new ReturnStmt((Expr*)0);
|
|
}
|
|
}
|
|
// we have a non-void function with an expression, continue checking
|
|
QualType rhsType = RetValExp->getType();
|
|
|
|
// C99 6.8.6.4p3(136): The return statement is not an assignment. The
|
|
// overlap restriction of subclause 6.5.16.1 does not apply to the case of
|
|
// function return.
|
|
AssignmentCheckResult result = CheckSingleAssignmentConstraints(lhsType,
|
|
RetValExp);
|
|
bool hadError = false;
|
|
|
|
// decode the result (notice that extensions still return a type).
|
|
switch (result) {
|
|
case Compatible:
|
|
break;
|
|
case Incompatible:
|
|
Diag(ReturnLoc, diag::err_typecheck_return_incompatible,
|
|
lhsType.getAsString(), rhsType.getAsString(),
|
|
RetValExp->getSourceRange());
|
|
hadError = true;
|
|
break;
|
|
case PointerFromInt:
|
|
// check for null pointer constant (C99 6.3.2.3p3)
|
|
if (!RetValExp->isNullPointerConstant(Context)) {
|
|
Diag(ReturnLoc, diag::ext_typecheck_return_pointer_int,
|
|
lhsType.getAsString(), rhsType.getAsString(),
|
|
RetValExp->getSourceRange());
|
|
}
|
|
break;
|
|
case IntFromPointer:
|
|
Diag(ReturnLoc, diag::ext_typecheck_return_pointer_int,
|
|
lhsType.getAsString(), rhsType.getAsString(),
|
|
RetValExp->getSourceRange());
|
|
break;
|
|
case IncompatiblePointer:
|
|
Diag(ReturnLoc, diag::ext_typecheck_return_incompatible_pointer,
|
|
lhsType.getAsString(), rhsType.getAsString(),
|
|
RetValExp->getSourceRange());
|
|
break;
|
|
case CompatiblePointerDiscardsQualifiers:
|
|
Diag(ReturnLoc, diag::ext_typecheck_return_discards_qualifiers,
|
|
lhsType.getAsString(), rhsType.getAsString(),
|
|
RetValExp->getSourceRange());
|
|
break;
|
|
}
|
|
return new ReturnStmt((Expr*)RetValExp);
|
|
}
|
|
|