2006-11-10 05:07:45 +00:00
|
|
|
//===--- SemaStmt.cpp - Semantic Analysis for Statements ------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-29 19:59:25 +00:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2006-11-10 05:07:45 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements semantic analysis for statements.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Sema.h"
|
2008-11-22 21:04:56 +00:00
|
|
|
#include "clang/AST/APValue.h"
|
2007-08-23 05:46:52 +00:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2008-08-11 05:35:13 +00:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2009-11-23 13:46:08 +00:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2009-08-16 16:57:27 +00:00
|
|
|
#include "clang/AST/ExprObjC.h"
|
2009-04-26 01:32:48 +00:00
|
|
|
#include "clang/AST/StmtObjC.h"
|
|
|
|
#include "clang/AST/StmtCXX.h"
|
2009-11-23 13:46:08 +00:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2007-11-25 00:25:21 +00:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2009-07-29 17:15:45 +00:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2006-11-10 05:07:45 +00:00
|
|
|
using namespace clang;
|
|
|
|
|
2009-05-17 21:11:30 +00:00
|
|
|
Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) {
|
|
|
|
Expr *E = expr->takeAs<Expr>();
|
2007-09-16 14:56:35 +00:00
|
|
|
assert(E && "ActOnExprStmt(): missing expression");
|
2009-09-03 00:43:07 +00:00
|
|
|
if (E->getType()->isObjCInterfaceType()) {
|
|
|
|
if (LangOpts.ObjCNonFragileABI)
|
|
|
|
Diag(E->getLocEnd(), diag::err_indirection_requires_nonfragile_object)
|
|
|
|
<< E->getType();
|
|
|
|
else
|
|
|
|
Diag(E->getLocEnd(), diag::err_direct_interface_unsupported)
|
|
|
|
<< E->getType();
|
|
|
|
return StmtError();
|
|
|
|
}
|
2008-07-25 23:18:17 +00:00
|
|
|
// C99 6.8.3p2: The expression in an expression statement is evaluated as a
|
|
|
|
// void expression for its side effects. Conversion to void allows any
|
|
|
|
// operand, even incomplete types.
|
2008-12-21 12:04:03 +00:00
|
|
|
|
2008-07-25 23:18:17 +00:00
|
|
|
// Same thing in for stmt first clause (when expr) and third clause.
|
2008-12-21 12:04:03 +00:00
|
|
|
return Owned(static_cast<Stmt*>(E));
|
2007-06-27 05:38:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-21 12:04:03 +00:00
|
|
|
Sema::OwningStmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc) {
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) NullStmt(SemiLoc));
|
2007-05-28 01:45:28 +00:00
|
|
|
}
|
|
|
|
|
2009-03-29 16:50:03 +00:00
|
|
|
Sema::OwningStmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg,
|
2008-12-21 12:04:03 +00:00
|
|
|
SourceLocation StartLoc,
|
|
|
|
SourceLocation EndLoc) {
|
2009-04-12 20:13:14 +00:00
|
|
|
DeclGroupRef DG = dg.getAsVal<DeclGroupRef>();
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-29 16:50:03 +00:00
|
|
|
// If we have an invalid decl, just return an error.
|
2009-04-12 20:13:14 +00:00
|
|
|
if (DG.isNull()) return StmtError();
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-04 04:23:07 +00:00
|
|
|
return Owned(new (Context) DeclStmt(DG, StartLoc, EndLoc));
|
2007-05-29 22:59:26 +00:00
|
|
|
}
|
2006-11-10 05:07:45 +00:00
|
|
|
|
2009-11-19 22:12:37 +00:00
|
|
|
void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
|
|
|
|
DeclGroupRef DG = dg.getAsVal<DeclGroupRef>();
|
|
|
|
|
|
|
|
// If we have an invalid decl, just return.
|
|
|
|
if (DG.isNull() || !DG.isSingleDecl()) return;
|
|
|
|
// suppress any potential 'unused variable' warning.
|
|
|
|
DG.getSingleDecl()->setUsed();
|
|
|
|
}
|
|
|
|
|
2009-07-30 22:17:18 +00:00
|
|
|
void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
|
2009-07-30 22:39:03 +00:00
|
|
|
const Expr *E = dyn_cast_or_null<Expr>(S);
|
2009-07-30 22:17:18 +00:00
|
|
|
if (!E)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Ignore expressions that have void type.
|
|
|
|
if (E->getType()->isVoidType())
|
|
|
|
return;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-30 22:17:18 +00:00
|
|
|
SourceLocation Loc;
|
|
|
|
SourceRange R1, R2;
|
2009-11-03 23:25:48 +00:00
|
|
|
if (!E->isUnusedResultAWarning(Loc, R1, R2, Context))
|
2009-07-30 22:17:18 +00:00
|
|
|
return;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-08-16 16:57:27 +00:00
|
|
|
// Okay, we have an unused result. Depending on what the base expression is,
|
|
|
|
// we might want to make a more specific diagnostic. Check for one of these
|
|
|
|
// cases now.
|
|
|
|
unsigned DiagID = diag::warn_unused_expr;
|
|
|
|
E = E->IgnoreParens();
|
2009-08-20 17:02:02 +00:00
|
|
|
if (isa<ObjCImplicitSetterGetterRefExpr>(E))
|
2009-08-16 16:57:27 +00:00
|
|
|
DiagID = diag::warn_unused_property_expr;
|
2009-10-13 04:53:48 +00:00
|
|
|
|
|
|
|
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
|
|
|
|
// If the callee has attribute pure, const, or warn_unused_result, warn with
|
|
|
|
// a more specific message to make it clear what is happening.
|
|
|
|
if (const FunctionDecl *FD = CE->getDirectCallee()) {
|
|
|
|
if (FD->getAttr<WarnUnusedResultAttr>()) {
|
|
|
|
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (FD->getAttr<PureAttr>()) {
|
|
|
|
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "pure";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (FD->getAttr<ConstAttr>()) {
|
|
|
|
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "const";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-08-16 16:57:27 +00:00
|
|
|
Diag(Loc, DiagID) << R1 << R2;
|
2009-07-30 22:17:18 +00:00
|
|
|
}
|
|
|
|
|
2008-12-21 12:04:03 +00:00
|
|
|
Action::OwningStmtResult
|
2007-09-16 14:56:35 +00:00
|
|
|
Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
|
2008-12-21 12:04:03 +00:00
|
|
|
MultiStmtArg elts, bool isStmtExpr) {
|
|
|
|
unsigned NumElts = elts.size();
|
|
|
|
Stmt **Elts = reinterpret_cast<Stmt**>(elts.release());
|
2007-08-27 04:29:41 +00:00
|
|
|
// If we're in C89 mode, check that we don't have any decls after stmts. If
|
|
|
|
// so, emit an extension diagnostic.
|
|
|
|
if (!getLangOptions().C99 && !getLangOptions().CPlusPlus) {
|
|
|
|
// Note that __extension__ can be around a decl.
|
|
|
|
unsigned i = 0;
|
|
|
|
// Skip over all declarations.
|
|
|
|
for (; i != NumElts && isa<DeclStmt>(Elts[i]); ++i)
|
|
|
|
/*empty*/;
|
|
|
|
|
|
|
|
// We found the end of the list or a statement. Scan for another declstmt.
|
|
|
|
for (; i != NumElts && !isa<DeclStmt>(Elts[i]); ++i)
|
|
|
|
/*empty*/;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-08-27 04:29:41 +00:00
|
|
|
if (i != NumElts) {
|
2009-01-20 01:17:11 +00:00
|
|
|
Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin();
|
2007-08-27 04:29:41 +00:00
|
|
|
Diag(D->getLocation(), diag::ext_mixed_decls_code);
|
|
|
|
}
|
|
|
|
}
|
2007-08-31 21:49:55 +00:00
|
|
|
// Warn about unused expressions in statements.
|
|
|
|
for (unsigned i = 0; i != NumElts; ++i) {
|
2009-07-30 22:17:18 +00:00
|
|
|
// Ignore statements that are last in a statement expression.
|
|
|
|
if (isStmtExpr && i == NumElts - 1)
|
2007-08-31 21:49:55 +00:00
|
|
|
continue;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-30 22:17:18 +00:00
|
|
|
DiagnoseUnusedExprResult(Elts[i]);
|
2007-08-31 21:49:55 +00:00
|
|
|
}
|
2008-12-21 12:04:03 +00:00
|
|
|
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) CompoundStmt(Context, Elts, NumElts, L, R));
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
|
|
|
|
2008-12-28 16:13:43 +00:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprArg lhsval,
|
|
|
|
SourceLocation DotDotDotLoc, ExprArg rhsval,
|
2009-03-04 04:23:07 +00:00
|
|
|
SourceLocation ColonLoc) {
|
2008-12-28 16:13:43 +00:00
|
|
|
assert((lhsval.get() != 0) && "missing expression in case statement");
|
|
|
|
|
2007-05-08 21:09:37 +00:00
|
|
|
// C99 6.8.4.2p3: The expression shall be an integer constant.
|
2009-09-09 15:08:12 +00:00
|
|
|
// However, GCC allows any evaluatable integer expression.
|
2008-12-28 16:13:43 +00:00
|
|
|
Expr *LHSVal = static_cast<Expr*>(lhsval.get());
|
2009-09-09 15:08:12 +00:00
|
|
|
if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() &&
|
2009-05-15 23:57:33 +00:00
|
|
|
VerifyIntegerConstantExpression(LHSVal))
|
2009-03-04 04:23:07 +00:00
|
|
|
return StmtError();
|
2007-05-08 21:09:37 +00:00
|
|
|
|
2007-07-18 02:28:47 +00:00
|
|
|
// GCC extension: The expression shall be an integer constant.
|
2008-12-28 16:13:43 +00:00
|
|
|
|
|
|
|
Expr *RHSVal = static_cast<Expr*>(rhsval.get());
|
2009-05-15 23:57:33 +00:00
|
|
|
if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() &&
|
|
|
|
VerifyIntegerConstantExpression(RHSVal)) {
|
2007-08-23 05:46:52 +00:00
|
|
|
RHSVal = 0; // Recover by just forgetting about it.
|
2008-12-28 16:13:43 +00:00
|
|
|
rhsval = 0;
|
|
|
|
}
|
|
|
|
|
2009-04-18 20:10:59 +00:00
|
|
|
if (getSwitchStack().empty()) {
|
2007-07-23 17:05:23 +00:00
|
|
|
Diag(CaseLoc, diag::err_case_not_in_switch);
|
2009-03-04 04:23:07 +00:00
|
|
|
return StmtError();
|
2007-07-23 17:05:23 +00:00
|
|
|
}
|
2007-06-03 01:44:43 +00:00
|
|
|
|
2008-12-28 16:13:43 +00:00
|
|
|
// Only now release the smart pointers.
|
|
|
|
lhsval.release();
|
|
|
|
rhsval.release();
|
2009-05-15 23:57:33 +00:00
|
|
|
CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc,
|
|
|
|
ColonLoc);
|
2009-04-18 20:10:59 +00:00
|
|
|
getSwitchStack().back()->addSwitchCase(CS);
|
2008-12-28 16:13:43 +00:00
|
|
|
return Owned(CS);
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
|
|
|
|
2009-03-04 04:23:07 +00:00
|
|
|
/// ActOnCaseStmtBody - This installs a statement as the body of a case.
|
|
|
|
void Sema::ActOnCaseStmtBody(StmtTy *caseStmt, StmtArg subStmt) {
|
|
|
|
CaseStmt *CS = static_cast<CaseStmt*>(caseStmt);
|
2009-05-01 19:30:39 +00:00
|
|
|
Stmt *SubStmt = subStmt.takeAs<Stmt>();
|
2009-03-04 04:23:07 +00:00
|
|
|
CS->setSubStmt(SubStmt);
|
|
|
|
}
|
|
|
|
|
2008-12-28 16:13:43 +00:00
|
|
|
Action::OwningStmtResult
|
2009-09-09 15:08:12 +00:00
|
|
|
Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
|
2008-12-28 16:13:43 +00:00
|
|
|
StmtArg subStmt, Scope *CurScope) {
|
2009-05-01 19:30:39 +00:00
|
|
|
Stmt *SubStmt = subStmt.takeAs<Stmt>();
|
2008-12-28 16:13:43 +00:00
|
|
|
|
2009-04-18 20:10:59 +00:00
|
|
|
if (getSwitchStack().empty()) {
|
2007-07-21 03:00:26 +00:00
|
|
|
Diag(DefaultLoc, diag::err_default_not_in_switch);
|
2008-12-28 16:13:43 +00:00
|
|
|
return Owned(SubStmt);
|
2007-07-21 03:00:26 +00:00
|
|
|
}
|
2008-12-28 16:13:43 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
DefaultStmt *DS = new (Context) DefaultStmt(DefaultLoc, ColonLoc, SubStmt);
|
2009-04-18 20:10:59 +00:00
|
|
|
getSwitchStack().back()->addSwitchCase(DS);
|
2008-12-28 16:13:43 +00:00
|
|
|
return Owned(DS);
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-11 00:38:46 +00:00
|
|
|
Action::OwningStmtResult
|
2007-09-16 14:56:35 +00:00
|
|
|
Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
|
2009-01-11 00:38:46 +00:00
|
|
|
SourceLocation ColonLoc, StmtArg subStmt) {
|
2009-05-01 19:30:39 +00:00
|
|
|
Stmt *SubStmt = subStmt.takeAs<Stmt>();
|
2007-05-28 06:28:18 +00:00
|
|
|
// Look up the record for this label identifier.
|
2009-04-18 20:01:55 +00:00
|
|
|
LabelStmt *&LabelDecl = getLabelMap()[II];
|
2009-01-11 00:38:46 +00:00
|
|
|
|
2007-05-28 06:28:18 +00:00
|
|
|
// If not forward referenced or defined already, just create a new LabelStmt.
|
2009-03-13 15:38:40 +00:00
|
|
|
if (LabelDecl == 0)
|
|
|
|
return Owned(LabelDecl = new (Context) LabelStmt(IdentLoc, II, SubStmt));
|
2009-01-11 00:38:46 +00:00
|
|
|
|
2007-05-28 06:56:27 +00:00
|
|
|
assert(LabelDecl->getID() == II && "Label mismatch!");
|
2009-01-11 00:38:46 +00:00
|
|
|
|
2007-05-28 06:28:18 +00:00
|
|
|
// Otherwise, this label was either forward reference or multiply defined. If
|
|
|
|
// multiply defined, reject it now.
|
|
|
|
if (LabelDecl->getSubStmt()) {
|
2008-11-23 21:45:46 +00:00
|
|
|
Diag(IdentLoc, diag::err_redefinition_of_label) << LabelDecl->getID();
|
2008-11-23 23:12:31 +00:00
|
|
|
Diag(LabelDecl->getIdentLoc(), diag::note_previous_definition);
|
2009-01-11 00:38:46 +00:00
|
|
|
return Owned(SubStmt);
|
2007-05-28 06:28:18 +00:00
|
|
|
}
|
2009-01-11 00:38:46 +00:00
|
|
|
|
2007-05-28 06:28:18 +00:00
|
|
|
// Otherwise, this label was forward declared, and we just found its real
|
|
|
|
// definition. Fill in the forward definition and return it.
|
|
|
|
LabelDecl->setIdentLoc(IdentLoc);
|
2007-07-21 03:00:26 +00:00
|
|
|
LabelDecl->setSubStmt(SubStmt);
|
2009-01-11 00:38:46 +00:00
|
|
|
return Owned(LabelDecl);
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-11 00:38:46 +00:00
|
|
|
Action::OwningStmtResult
|
2009-11-25 00:27:52 +00:00
|
|
|
Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar,
|
2009-01-11 00:38:46 +00:00
|
|
|
StmtArg ThenVal, SourceLocation ElseLoc,
|
|
|
|
StmtArg ElseVal) {
|
2009-05-17 18:26:53 +00:00
|
|
|
OwningExprResult CondResult(CondVal.release());
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-11-23 23:44:04 +00:00
|
|
|
VarDecl *ConditionVar = 0;
|
2009-11-25 00:27:52 +00:00
|
|
|
if (CondVar.get()) {
|
|
|
|
ConditionVar = CondVar.getAs<VarDecl>();
|
|
|
|
CondResult = CheckConditionVariable(ConditionVar);
|
|
|
|
if (CondResult.isInvalid())
|
|
|
|
return StmtError();
|
2009-11-23 23:44:04 +00:00
|
|
|
}
|
2009-11-25 00:27:52 +00:00
|
|
|
Expr *ConditionExpr = CondResult.takeAs<Expr>();
|
|
|
|
if (!ConditionExpr)
|
|
|
|
return StmtError();
|
2009-11-23 23:44:04 +00:00
|
|
|
|
2009-11-25 00:27:52 +00:00
|
|
|
if (CheckBooleanCondition(ConditionExpr, IfLoc)) {
|
|
|
|
CondResult = ConditionExpr;
|
2009-10-12 21:59:07 +00:00
|
|
|
return StmtError();
|
2009-05-15 18:53:42 +00:00
|
|
|
}
|
2009-01-11 00:38:46 +00:00
|
|
|
|
2009-05-01 19:49:17 +00:00
|
|
|
Stmt *thenStmt = ThenVal.takeAs<Stmt>();
|
2009-07-30 22:39:03 +00:00
|
|
|
DiagnoseUnusedExprResult(thenStmt);
|
2007-05-29 02:14:17 +00:00
|
|
|
|
2007-10-10 20:50:11 +00:00
|
|
|
// Warn if the if block has a null body without an else value.
|
|
|
|
// this helps prevent bugs due to typos, such as
|
|
|
|
// if (condition);
|
|
|
|
// do_stuff();
|
2009-09-09 15:08:12 +00:00
|
|
|
if (!ElseVal.get()) {
|
2007-10-10 20:50:11 +00:00
|
|
|
if (NullStmt* stmt = dyn_cast<NullStmt>(thenStmt))
|
|
|
|
Diag(stmt->getSemiLoc(), diag::warn_empty_if_body);
|
|
|
|
}
|
|
|
|
|
2009-07-30 22:39:03 +00:00
|
|
|
Stmt *elseStmt = ElseVal.takeAs<Stmt>();
|
|
|
|
DiagnoseUnusedExprResult(elseStmt);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-17 18:26:53 +00:00
|
|
|
CondResult.release();
|
2009-11-25 00:27:52 +00:00
|
|
|
return Owned(new (Context) IfStmt(IfLoc, ConditionVar, ConditionExpr,
|
|
|
|
thenStmt, ElseLoc, elseStmt));
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
2007-05-29 02:14:17 +00:00
|
|
|
|
2009-01-11 00:38:46 +00:00
|
|
|
Action::OwningStmtResult
|
2009-11-25 00:27:52 +00:00
|
|
|
Sema::ActOnStartOfSwitchStmt(FullExprArg cond, DeclPtrTy CondVar) {
|
|
|
|
OwningExprResult CondResult(cond.release());
|
|
|
|
|
2009-11-24 17:07:59 +00:00
|
|
|
VarDecl *ConditionVar = 0;
|
2009-11-25 00:27:52 +00:00
|
|
|
if (CondVar.get()) {
|
|
|
|
ConditionVar = CondVar.getAs<VarDecl>();
|
|
|
|
CondResult = CheckConditionVariable(ConditionVar);
|
|
|
|
if (CondResult.isInvalid())
|
|
|
|
return StmtError();
|
2009-11-24 17:07:59 +00:00
|
|
|
}
|
2009-11-25 00:27:52 +00:00
|
|
|
Expr *ConditionExpr = CondResult.takeAs<Expr>();
|
|
|
|
if (!ConditionExpr)
|
|
|
|
return StmtError();
|
2009-11-24 17:07:59 +00:00
|
|
|
|
2009-11-25 00:27:52 +00:00
|
|
|
CondResult.release();
|
|
|
|
SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar, ConditionExpr);
|
2009-04-18 20:10:59 +00:00
|
|
|
getSwitchStack().push_back(SS);
|
2009-01-11 00:38:46 +00:00
|
|
|
return Owned(SS);
|
2007-07-22 07:07:56 +00:00
|
|
|
}
|
2007-07-18 02:28:47 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
|
|
|
|
/// the specified width and sign. If an overflow occurs, detect it and emit
|
|
|
|
/// the specified diagnostic.
|
|
|
|
void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
|
|
|
|
unsigned NewWidth, bool NewSign,
|
2009-09-09 15:08:12 +00:00
|
|
|
SourceLocation Loc,
|
2007-08-23 05:46:52 +00:00
|
|
|
unsigned DiagID) {
|
|
|
|
// Perform a conversion to the promoted condition type if needed.
|
|
|
|
if (NewWidth > Val.getBitWidth()) {
|
|
|
|
// If this is an extension, just do it.
|
|
|
|
llvm::APSInt OldVal(Val);
|
|
|
|
Val.extend(NewWidth);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
// If the input was signed and negative and the output is unsigned,
|
|
|
|
// warn.
|
|
|
|
if (!NewSign && OldVal.isSigned() && OldVal.isNegative())
|
2008-11-20 06:06:08 +00:00
|
|
|
Diag(Loc, DiagID) << OldVal.toString(10) << Val.toString(10);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
Val.setIsSigned(NewSign);
|
|
|
|
} else if (NewWidth < Val.getBitWidth()) {
|
|
|
|
// If this is a truncation, check for overflow.
|
|
|
|
llvm::APSInt ConvVal(Val);
|
|
|
|
ConvVal.trunc(NewWidth);
|
2007-08-23 22:08:35 +00:00
|
|
|
ConvVal.setIsSigned(NewSign);
|
2007-08-23 05:46:52 +00:00
|
|
|
ConvVal.extend(Val.getBitWidth());
|
2007-08-23 22:08:35 +00:00
|
|
|
ConvVal.setIsSigned(Val.isSigned());
|
2007-08-23 05:46:52 +00:00
|
|
|
if (ConvVal != Val)
|
2008-11-20 06:06:08 +00:00
|
|
|
Diag(Loc, DiagID) << Val.toString(10) << ConvVal.toString(10);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
// Regardless of whether a diagnostic was emitted, really do the
|
|
|
|
// truncation.
|
|
|
|
Val.trunc(NewWidth);
|
2007-08-23 22:08:35 +00:00
|
|
|
Val.setIsSigned(NewSign);
|
2007-08-23 05:46:52 +00:00
|
|
|
} else if (NewSign != Val.isSigned()) {
|
|
|
|
// Convert the sign to match the sign of the condition. This can cause
|
|
|
|
// overflow as well: unsigned(INTMIN)
|
|
|
|
llvm::APSInt OldVal(Val);
|
|
|
|
Val.setIsSigned(NewSign);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
if (Val.isNegative()) // Sign bit changes meaning.
|
2008-11-20 06:06:08 +00:00
|
|
|
Diag(Loc, DiagID) << OldVal.toString(10) << Val.toString(10);
|
2007-08-23 05:46:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-23 18:29:20 +00:00
|
|
|
namespace {
|
|
|
|
struct CaseCompareFunctor {
|
|
|
|
bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
|
|
|
|
const llvm::APSInt &RHS) {
|
|
|
|
return LHS.first < RHS;
|
|
|
|
}
|
2007-09-03 18:31:57 +00:00
|
|
|
bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
|
|
|
|
const std::pair<llvm::APSInt, CaseStmt*> &RHS) {
|
|
|
|
return LHS.first < RHS.first;
|
|
|
|
}
|
2007-08-23 18:29:20 +00:00
|
|
|
bool operator()(const llvm::APSInt &LHS,
|
|
|
|
const std::pair<llvm::APSInt, CaseStmt*> &RHS) {
|
|
|
|
return LHS < RHS.first;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2007-09-21 18:15:22 +00:00
|
|
|
/// CmpCaseVals - Comparison predicate for sorting case values.
|
|
|
|
///
|
|
|
|
static bool CmpCaseVals(const std::pair<llvm::APSInt, CaseStmt*>& lhs,
|
|
|
|
const std::pair<llvm::APSInt, CaseStmt*>& rhs) {
|
|
|
|
if (lhs.first < rhs.first)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (lhs.first == rhs.first &&
|
|
|
|
lhs.second->getCaseLoc().getRawEncoding()
|
|
|
|
< rhs.second->getCaseLoc().getRawEncoding())
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-10-16 16:45:22 +00:00
|
|
|
/// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of
|
|
|
|
/// potentially integral-promoted expression @p expr.
|
|
|
|
static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) {
|
|
|
|
const ImplicitCastExpr *ImplicitCast =
|
|
|
|
dyn_cast_or_null<ImplicitCastExpr>(expr);
|
|
|
|
if (ImplicitCast != NULL) {
|
|
|
|
const Expr *ExprBeforePromotion = ImplicitCast->getSubExpr();
|
|
|
|
QualType TypeBeforePromotion = ExprBeforePromotion->getType();
|
|
|
|
if (TypeBeforePromotion->isIntegralType()) {
|
|
|
|
return TypeBeforePromotion;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return expr->getType();
|
|
|
|
}
|
|
|
|
|
2009-11-25 04:55:54 +00:00
|
|
|
/// \brief Check (and possibly convert) the condition in a switch
|
|
|
|
/// statement in C++.
|
|
|
|
static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc,
|
|
|
|
Expr *&CondExpr) {
|
|
|
|
if (CondExpr->isTypeDependent())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
QualType CondType = CondExpr->getType();
|
|
|
|
|
|
|
|
// C++ 6.4.2.p2:
|
|
|
|
// The condition shall be of integral type, enumeration type, or of a class
|
|
|
|
// type for which a single conversion function to integral or enumeration
|
|
|
|
// type exists (12.3). If the condition is of class type, the condition is
|
|
|
|
// converted by calling that conversion function, and the result of the
|
|
|
|
// conversion is used in place of the original condition for the remainder
|
|
|
|
// of this section. Integral promotions are performed.
|
|
|
|
|
|
|
|
// Make sure that the condition expression has a complete type,
|
|
|
|
// otherwise we'll never find any conversions.
|
|
|
|
if (S.RequireCompleteType(SwitchLoc, CondType,
|
|
|
|
PDiag(diag::err_switch_incomplete_class_type)
|
|
|
|
<< CondExpr->getSourceRange()))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
llvm::SmallVector<CXXConversionDecl *, 4> ViableConversions;
|
|
|
|
llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions;
|
|
|
|
if (const RecordType *RecordTy = CondType->getAs<RecordType>()) {
|
|
|
|
const UnresolvedSet *Conversions
|
|
|
|
= cast<CXXRecordDecl>(RecordTy->getDecl())
|
|
|
|
->getVisibleConversionFunctions();
|
|
|
|
for (UnresolvedSet::iterator I = Conversions->begin(),
|
|
|
|
E = Conversions->end(); I != E; ++I) {
|
|
|
|
if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*I))
|
|
|
|
if (Conversion->getConversionType().getNonReferenceType()
|
|
|
|
->isIntegralType()) {
|
|
|
|
if (Conversion->isExplicit())
|
|
|
|
ExplicitConversions.push_back(Conversion);
|
|
|
|
else
|
|
|
|
ViableConversions.push_back(Conversion);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (ViableConversions.size()) {
|
|
|
|
case 0:
|
|
|
|
if (ExplicitConversions.size() == 1) {
|
|
|
|
// The user probably meant to invoke the given explicit
|
|
|
|
// conversion; use it.
|
|
|
|
QualType ConvTy
|
|
|
|
= ExplicitConversions[0]->getConversionType()
|
|
|
|
.getNonReferenceType();
|
|
|
|
std::string TypeStr;
|
|
|
|
ConvTy.getAsStringInternal(TypeStr, S.Context.PrintingPolicy);
|
|
|
|
|
|
|
|
S.Diag(SwitchLoc, diag::err_switch_explicit_conversion)
|
|
|
|
<< CondType << ConvTy << CondExpr->getSourceRange()
|
|
|
|
<< CodeModificationHint::CreateInsertion(CondExpr->getLocStart(),
|
|
|
|
"static_cast<" + TypeStr + ">(")
|
|
|
|
<< CodeModificationHint::CreateInsertion(
|
|
|
|
S.PP.getLocForEndOfToken(CondExpr->getLocEnd()),
|
|
|
|
")");
|
|
|
|
S.Diag(ExplicitConversions[0]->getLocation(),
|
|
|
|
diag::note_switch_conversion)
|
|
|
|
<< ConvTy->isEnumeralType() << ConvTy;
|
|
|
|
|
|
|
|
// If we aren't in a SFINAE context, build a call to the
|
|
|
|
// explicit conversion function.
|
|
|
|
if (S.isSFINAEContext())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ExplicitConversions[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We'll complain below about a non-integral condition type.
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
// Apply this conversion.
|
|
|
|
CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ViableConversions[0]);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
S.Diag(SwitchLoc, diag::err_switch_multiple_conversions)
|
|
|
|
<< CondType << CondExpr->getSourceRange();
|
|
|
|
for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
|
|
|
|
QualType ConvTy
|
|
|
|
= ViableConversions[I]->getConversionType().getNonReferenceType();
|
|
|
|
S.Diag(ViableConversions[I]->getLocation(),
|
|
|
|
diag::note_switch_conversion)
|
|
|
|
<< ConvTy->isEnumeralType() << ConvTy;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-01-11 00:38:46 +00:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
|
|
|
|
StmtArg Body) {
|
2009-05-01 19:49:17 +00:00
|
|
|
Stmt *BodyStmt = Body.takeAs<Stmt>();
|
2009-01-11 00:38:46 +00:00
|
|
|
|
2009-04-18 20:10:59 +00:00
|
|
|
SwitchStmt *SS = getSwitchStack().back();
|
2009-01-11 00:38:46 +00:00
|
|
|
assert(SS == (SwitchStmt*)Switch.get() && "switch stack missing push/pop!");
|
|
|
|
|
2007-09-01 21:08:38 +00:00
|
|
|
SS->setBody(BodyStmt, SwitchLoc);
|
2009-09-09 15:08:12 +00:00
|
|
|
getSwitchStack().pop_back();
|
2007-07-22 07:07:56 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
Expr *CondExpr = SS->getCond();
|
2009-11-23 13:46:08 +00:00
|
|
|
QualType CondTypeBeforePromotion =
|
|
|
|
GetTypeBeforeIntegralPromotion(CondExpr);
|
2009-01-11 00:38:46 +00:00
|
|
|
|
2009-11-25 05:02:21 +00:00
|
|
|
if (getLangOptions().CPlusPlus &&
|
|
|
|
CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr))
|
2009-11-25 04:55:54 +00:00
|
|
|
return StmtError();
|
2009-11-25 05:02:21 +00:00
|
|
|
|
|
|
|
QualType CondType = CondExpr->getType();
|
2009-11-23 13:46:08 +00:00
|
|
|
SS->setCond(CondExpr);
|
|
|
|
|
2009-10-16 16:45:22 +00:00
|
|
|
// C++ 6.4.2.p2:
|
|
|
|
// Integral promotions are performed (on the switch condition).
|
|
|
|
//
|
|
|
|
// A case value unrepresentable by the original switch condition
|
|
|
|
// type (before the promotion) doesn't make sense, even when it can
|
|
|
|
// be represented by the promoted type. Therefore we need to find
|
|
|
|
// the pre-promotion type of the switch condition.
|
2009-10-17 19:32:54 +00:00
|
|
|
if (!CondExpr->isTypeDependent()) {
|
|
|
|
if (!CondType->isIntegerType()) { // C99 6.8.4.2p1
|
|
|
|
Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer)
|
|
|
|
<< CondType << CondExpr->getSourceRange();
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
2009-11-25 05:02:21 +00:00
|
|
|
UsualUnaryConversions(CondExpr);
|
|
|
|
|
2009-10-17 19:32:54 +00:00
|
|
|
if (CondTypeBeforePromotion->isBooleanType()) {
|
|
|
|
// switch(bool_expr) {...} is often a programmer error, e.g.
|
|
|
|
// switch(n && mask) { ... } // Doh - should be "n & mask".
|
|
|
|
// One can always use an if statement instead of switch(bool_expr).
|
|
|
|
Diag(SwitchLoc, diag::warn_bool_switch_condition)
|
|
|
|
<< CondExpr->getSourceRange();
|
|
|
|
}
|
2007-07-22 07:07:56 +00:00
|
|
|
}
|
2009-01-11 00:38:46 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
// Get the bitwidth of the switched-on value before promotions. We must
|
|
|
|
// convert the integer case values to this width before comparison.
|
2009-09-09 15:08:12 +00:00
|
|
|
bool HasDependentValue
|
2009-05-15 23:57:33 +00:00
|
|
|
= CondExpr->isTypeDependent() || CondExpr->isValueDependent();
|
2009-09-09 15:08:12 +00:00
|
|
|
unsigned CondWidth
|
2009-05-15 23:57:33 +00:00
|
|
|
= HasDependentValue? 0
|
2009-10-16 16:45:22 +00:00
|
|
|
: static_cast<unsigned>(Context.getTypeSize(CondTypeBeforePromotion));
|
|
|
|
bool CondIsSigned = CondTypeBeforePromotion->isSignedIntegerType();
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
// Accumulate all of the case values in a vector so that we can sort them
|
|
|
|
// and detect duplicates. This vector contains the APInt for the case after
|
|
|
|
// it has been converted to the condition type.
|
2007-08-23 18:29:20 +00:00
|
|
|
typedef llvm::SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy;
|
|
|
|
CaseValsTy CaseVals;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
// Keep track of any GNU case ranges we see. The APSInt is the low value.
|
|
|
|
std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRanges;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
DefaultStmt *TheDefaultStmt = 0;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-08-23 06:23:56 +00:00
|
|
|
bool CaseListIsErroneous = false;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
for (SwitchCase *SC = SS->getSwitchCaseList(); SC && !HasDependentValue;
|
2007-07-22 07:07:56 +00:00
|
|
|
SC = SC->getNextSwitchCase()) {
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-07-22 07:07:56 +00:00
|
|
|
if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC)) {
|
2007-08-23 05:46:52 +00:00
|
|
|
if (TheDefaultStmt) {
|
|
|
|
Diag(DS->getDefaultLoc(), diag::err_multiple_default_labels_defined);
|
2008-11-23 23:12:31 +00:00
|
|
|
Diag(TheDefaultStmt->getDefaultLoc(), diag::note_duplicate_case_prev);
|
2009-01-11 00:38:46 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
// FIXME: Remove the default statement from the switch block so that
|
2009-05-16 07:39:55 +00:00
|
|
|
// we'll return a valid AST. This requires recursing down the AST and
|
|
|
|
// finding it, not something we are set up to do right now. For now,
|
|
|
|
// just lop the entire switch stmt out of the AST.
|
2007-08-23 06:23:56 +00:00
|
|
|
CaseListIsErroneous = true;
|
2007-07-22 07:07:56 +00:00
|
|
|
}
|
2007-08-23 05:46:52 +00:00
|
|
|
TheDefaultStmt = DS;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
} else {
|
|
|
|
CaseStmt *CS = cast<CaseStmt>(SC);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
// We already verified that the expression has a i-c-e value (C99
|
|
|
|
// 6.8.4.2p3) - get that value now.
|
2008-01-16 19:17:22 +00:00
|
|
|
Expr *Lo = CS->getLHS();
|
2009-05-15 23:57:33 +00:00
|
|
|
|
|
|
|
if (Lo->isTypeDependent() || Lo->isValueDependent()) {
|
|
|
|
HasDependentValue = true;
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2008-11-22 21:04:56 +00:00
|
|
|
llvm::APSInt LoVal = Lo->EvaluateAsInt(Context);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-08-23 05:46:52 +00:00
|
|
|
// Convert the value to the same width/sign as the condition.
|
|
|
|
ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
|
|
|
|
CS->getLHS()->getLocStart(),
|
|
|
|
diag::warn_case_value_overflow);
|
2007-07-18 02:28:47 +00:00
|
|
|
|
2008-01-16 19:17:22 +00:00
|
|
|
// If the LHS is not the same type as the condition, insert an implicit
|
|
|
|
// cast.
|
2009-10-20 08:27:19 +00:00
|
|
|
ImpCastExprToType(Lo, CondType, CastExpr::CK_IntegralCast);
|
2008-01-16 19:17:22 +00:00
|
|
|
CS->setLHS(Lo);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-08-23 06:23:56 +00:00
|
|
|
// If this is a case range, remember it in CaseRanges, otherwise CaseVals.
|
2009-05-15 23:57:33 +00:00
|
|
|
if (CS->getRHS()) {
|
2009-09-09 15:08:12 +00:00
|
|
|
if (CS->getRHS()->isTypeDependent() ||
|
2009-05-15 23:57:33 +00:00
|
|
|
CS->getRHS()->isValueDependent()) {
|
|
|
|
HasDependentValue = true;
|
|
|
|
break;
|
|
|
|
}
|
2007-08-23 05:46:52 +00:00
|
|
|
CaseRanges.push_back(std::make_pair(LoVal, CS));
|
2009-09-09 15:08:12 +00:00
|
|
|
} else
|
2007-08-23 06:23:56 +00:00
|
|
|
CaseVals.push_back(std::make_pair(LoVal, CS));
|
2007-08-23 05:46:52 +00:00
|
|
|
}
|
|
|
|
}
|
2007-08-23 06:23:56 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
if (!HasDependentValue) {
|
|
|
|
// Sort all the scalar case values so we can easily detect duplicates.
|
|
|
|
std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals);
|
|
|
|
|
|
|
|
if (!CaseVals.empty()) {
|
|
|
|
for (unsigned i = 0, e = CaseVals.size()-1; i != e; ++i) {
|
|
|
|
if (CaseVals[i].first == CaseVals[i+1].first) {
|
|
|
|
// If we have a duplicate, report it.
|
|
|
|
Diag(CaseVals[i+1].second->getLHS()->getLocStart(),
|
|
|
|
diag::err_duplicate_case) << CaseVals[i].first.toString(10);
|
2009-09-09 15:08:12 +00:00
|
|
|
Diag(CaseVals[i].second->getLHS()->getLocStart(),
|
2009-05-15 23:57:33 +00:00
|
|
|
diag::note_duplicate_case_prev);
|
2009-05-16 07:39:55 +00:00
|
|
|
// FIXME: We really want to remove the bogus case stmt from the
|
|
|
|
// substmt, but we have no way to do this right now.
|
2009-05-15 23:57:33 +00:00
|
|
|
CaseListIsErroneous = true;
|
|
|
|
}
|
2007-08-23 17:48:14 +00:00
|
|
|
}
|
2007-08-23 06:23:56 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
// Detect duplicate case ranges, which usually don't exist at all in
|
|
|
|
// the first place.
|
|
|
|
if (!CaseRanges.empty()) {
|
|
|
|
// Sort all the case ranges by their low value so we can easily detect
|
|
|
|
// overlaps between ranges.
|
|
|
|
std::stable_sort(CaseRanges.begin(), CaseRanges.end());
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
// Scan the ranges, computing the high values and removing empty ranges.
|
|
|
|
std::vector<llvm::APSInt> HiVals;
|
|
|
|
for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) {
|
|
|
|
CaseStmt *CR = CaseRanges[i].second;
|
|
|
|
Expr *Hi = CR->getRHS();
|
|
|
|
llvm::APSInt HiVal = Hi->EvaluateAsInt(Context);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
// Convert the value to the same width/sign as the condition.
|
|
|
|
ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
|
|
|
|
CR->getRHS()->getLocStart(),
|
|
|
|
diag::warn_case_value_overflow);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
// If the LHS is not the same type as the condition, insert an implicit
|
|
|
|
// cast.
|
2009-10-20 08:27:19 +00:00
|
|
|
ImpCastExprToType(Hi, CondType, CastExpr::CK_IntegralCast);
|
2009-05-15 23:57:33 +00:00
|
|
|
CR->setRHS(Hi);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
// If the low value is bigger than the high value, the case is empty.
|
|
|
|
if (CaseRanges[i].first > HiVal) {
|
|
|
|
Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range)
|
|
|
|
<< SourceRange(CR->getLHS()->getLocStart(),
|
|
|
|
CR->getRHS()->getLocEnd());
|
|
|
|
CaseRanges.erase(CaseRanges.begin()+i);
|
|
|
|
--i, --e;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
HiVals.push_back(HiVal);
|
2007-08-23 18:29:20 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
// Rescan the ranges, looking for overlap with singleton values and other
|
|
|
|
// ranges. Since the range list is sorted, we only need to compare case
|
|
|
|
// ranges with their neighbors.
|
|
|
|
for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) {
|
|
|
|
llvm::APSInt &CRLo = CaseRanges[i].first;
|
|
|
|
llvm::APSInt &CRHi = HiVals[i];
|
|
|
|
CaseStmt *CR = CaseRanges[i].second;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
// Check to see whether the case range overlaps with any
|
|
|
|
// singleton cases.
|
|
|
|
CaseStmt *OverlapStmt = 0;
|
|
|
|
llvm::APSInt OverlapVal(32);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
// Find the smallest value >= the lower bound. If I is in the
|
|
|
|
// case range, then we have overlap.
|
|
|
|
CaseValsTy::iterator I = std::lower_bound(CaseVals.begin(),
|
|
|
|
CaseVals.end(), CRLo,
|
|
|
|
CaseCompareFunctor());
|
|
|
|
if (I != CaseVals.end() && I->first < CRHi) {
|
|
|
|
OverlapVal = I->first; // Found overlap with scalar.
|
|
|
|
OverlapStmt = I->second;
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
// Find the smallest value bigger than the upper bound.
|
|
|
|
I = std::upper_bound(I, CaseVals.end(), CRHi, CaseCompareFunctor());
|
|
|
|
if (I != CaseVals.begin() && (I-1)->first >= CRLo) {
|
|
|
|
OverlapVal = (I-1)->first; // Found overlap with scalar.
|
|
|
|
OverlapStmt = (I-1)->second;
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
// Check to see if this case stmt overlaps with the subsequent
|
|
|
|
// case range.
|
|
|
|
if (i && CRLo <= HiVals[i-1]) {
|
|
|
|
OverlapVal = HiVals[i-1]; // Found overlap with range.
|
|
|
|
OverlapStmt = CaseRanges[i-1].second;
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-15 23:57:33 +00:00
|
|
|
if (OverlapStmt) {
|
|
|
|
// If we have a duplicate, report it.
|
|
|
|
Diag(CR->getLHS()->getLocStart(), diag::err_duplicate_case)
|
|
|
|
<< OverlapVal.toString(10);
|
2009-09-09 15:08:12 +00:00
|
|
|
Diag(OverlapStmt->getLHS()->getLocStart(),
|
2009-05-15 23:57:33 +00:00
|
|
|
diag::note_duplicate_case_prev);
|
2009-05-16 07:39:55 +00:00
|
|
|
// FIXME: We really want to remove the bogus case stmt from the
|
|
|
|
// substmt, but we have no way to do this right now.
|
2009-05-15 23:57:33 +00:00
|
|
|
CaseListIsErroneous = true;
|
|
|
|
}
|
2007-08-23 18:29:20 +00:00
|
|
|
}
|
2007-08-23 06:23:56 +00:00
|
|
|
}
|
|
|
|
}
|
2009-05-15 23:57:33 +00:00
|
|
|
|
2009-05-16 07:39:55 +00:00
|
|
|
// FIXME: If the case list was broken is some way, we don't have a good system
|
|
|
|
// to patch it up. Instead, just return the whole substmt as broken.
|
2007-08-23 06:23:56 +00:00
|
|
|
if (CaseListIsErroneous)
|
2009-01-11 00:38:46 +00:00
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
Switch.release();
|
|
|
|
return Owned(SS);
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-16 23:28:06 +00:00
|
|
|
Action::OwningStmtResult
|
2009-11-25 00:27:52 +00:00
|
|
|
Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
|
|
|
|
DeclPtrTy CondVar, StmtArg Body) {
|
|
|
|
OwningExprResult CondResult(Cond.release());
|
|
|
|
|
2009-11-24 21:15:44 +00:00
|
|
|
VarDecl *ConditionVar = 0;
|
2009-11-25 00:27:52 +00:00
|
|
|
if (CondVar.get()) {
|
|
|
|
ConditionVar = CondVar.getAs<VarDecl>();
|
|
|
|
CondResult = CheckConditionVariable(ConditionVar);
|
|
|
|
if (CondResult.isInvalid())
|
|
|
|
return StmtError();
|
2009-11-24 21:15:44 +00:00
|
|
|
}
|
2009-11-25 00:27:52 +00:00
|
|
|
Expr *ConditionExpr = CondResult.takeAs<Expr>();
|
|
|
|
if (!ConditionExpr)
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
if (CheckBooleanCondition(ConditionExpr, WhileLoc)) {
|
|
|
|
CondResult = ConditionExpr;
|
2009-10-12 21:59:07 +00:00
|
|
|
return StmtError();
|
2009-05-15 21:45:53 +00:00
|
|
|
}
|
2007-05-29 02:14:17 +00:00
|
|
|
|
2009-07-30 22:39:03 +00:00
|
|
|
Stmt *bodyStmt = Body.takeAs<Stmt>();
|
|
|
|
DiagnoseUnusedExprResult(bodyStmt);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-11-25 00:27:52 +00:00
|
|
|
CondResult.release();
|
|
|
|
return Owned(new (Context) WhileStmt(ConditionVar, ConditionExpr, bodyStmt,
|
2009-11-24 21:15:44 +00:00
|
|
|
WhileLoc));
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-16 23:28:06 +00:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
|
2009-06-12 23:04:47 +00:00
|
|
|
SourceLocation WhileLoc, SourceLocation CondLParen,
|
|
|
|
ExprArg Cond, SourceLocation CondRParen) {
|
2009-05-01 19:49:17 +00:00
|
|
|
Expr *condExpr = Cond.takeAs<Expr>();
|
2007-09-16 14:56:35 +00:00
|
|
|
assert(condExpr && "ActOnDoStmt(): missing expression");
|
2009-01-16 23:28:06 +00:00
|
|
|
|
2009-10-12 21:59:07 +00:00
|
|
|
if (CheckBooleanCondition(condExpr, DoLoc)) {
|
2009-05-15 21:56:04 +00:00
|
|
|
Cond = condExpr;
|
2009-10-12 21:59:07 +00:00
|
|
|
return StmtError();
|
2009-05-15 21:56:04 +00:00
|
|
|
}
|
2007-05-29 02:14:17 +00:00
|
|
|
|
2009-07-30 22:39:03 +00:00
|
|
|
Stmt *bodyStmt = Body.takeAs<Stmt>();
|
|
|
|
DiagnoseUnusedExprResult(bodyStmt);
|
|
|
|
|
2009-01-16 23:28:06 +00:00
|
|
|
Cond.release();
|
2009-07-30 22:39:03 +00:00
|
|
|
return Owned(new (Context) DoStmt(bodyStmt, condExpr, DoLoc,
|
2009-06-12 23:04:47 +00:00
|
|
|
WhileLoc, CondRParen));
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-16 23:28:06 +00:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
|
2009-11-25 00:27:52 +00:00
|
|
|
StmtArg first, FullExprArg second, DeclPtrTy secondVar,
|
|
|
|
FullExprArg third,
|
2009-01-16 23:28:06 +00:00
|
|
|
SourceLocation RParenLoc, StmtArg body) {
|
|
|
|
Stmt *First = static_cast<Stmt*>(first.get());
|
|
|
|
|
2008-09-10 02:17:11 +00:00
|
|
|
if (!getLangOptions().CPlusPlus) {
|
|
|
|
if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) {
|
2008-11-20 06:38:18 +00:00
|
|
|
// C99 6.8.5p3: The declaration part of a 'for' statement shall only
|
|
|
|
// declare identifiers for objects having storage class 'auto' or
|
|
|
|
// 'register'.
|
2008-09-10 02:17:11 +00:00
|
|
|
for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
|
|
|
|
DI!=DE; ++DI) {
|
|
|
|
VarDecl *VD = dyn_cast<VarDecl>(*DI);
|
|
|
|
if (VD && VD->isBlockVarDecl() && !VD->hasLocalStorage())
|
|
|
|
VD = 0;
|
|
|
|
if (VD == 0)
|
|
|
|
Diag((*DI)->getLocation(), diag::err_non_variable_decl_in_for);
|
|
|
|
// FIXME: mark decl erroneous!
|
|
|
|
}
|
2007-08-28 05:03:08 +00:00
|
|
|
}
|
2007-05-29 02:14:17 +00:00
|
|
|
}
|
2009-11-25 00:27:52 +00:00
|
|
|
|
|
|
|
OwningExprResult SecondResult(second.release());
|
|
|
|
VarDecl *ConditionVar = 0;
|
|
|
|
if (secondVar.get()) {
|
|
|
|
ConditionVar = secondVar.getAs<VarDecl>();
|
|
|
|
SecondResult = CheckConditionVariable(ConditionVar);
|
|
|
|
if (SecondResult.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr *Second = SecondResult.takeAs<Expr>();
|
2009-10-12 21:59:07 +00:00
|
|
|
if (Second && CheckBooleanCondition(Second, ForLoc)) {
|
2009-11-25 00:27:52 +00:00
|
|
|
SecondResult = Second;
|
2009-10-12 21:59:07 +00:00
|
|
|
return StmtError();
|
2007-05-29 02:14:17 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-11-25 00:27:52 +00:00
|
|
|
Expr *Third = third.release().takeAs<Expr>();
|
|
|
|
Stmt *Body = static_cast<Stmt*>(body.get());
|
|
|
|
|
2009-08-01 01:39:59 +00:00
|
|
|
DiagnoseUnusedExprResult(First);
|
|
|
|
DiagnoseUnusedExprResult(Third);
|
2009-07-30 22:39:03 +00:00
|
|
|
DiagnoseUnusedExprResult(Body);
|
|
|
|
|
2009-01-16 23:28:06 +00:00
|
|
|
first.release();
|
|
|
|
body.release();
|
2009-11-25 00:27:52 +00:00
|
|
|
return Owned(new (Context) ForStmt(First, Second, ConditionVar, Third, Body,
|
|
|
|
ForLoc, LParenLoc, RParenLoc));
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-16 23:28:06 +00:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
|
|
|
|
SourceLocation LParenLoc,
|
|
|
|
StmtArg first, ExprArg second,
|
|
|
|
SourceLocation RParenLoc, StmtArg body) {
|
|
|
|
Stmt *First = static_cast<Stmt*>(first.get());
|
|
|
|
Expr *Second = static_cast<Expr*>(second.get());
|
|
|
|
Stmt *Body = static_cast<Stmt*>(body.get());
|
2008-01-10 20:33:58 +00:00
|
|
|
if (First) {
|
|
|
|
QualType FirstType;
|
|
|
|
if (DeclStmt *DS = dyn_cast<DeclStmt>(First)) {
|
2009-03-28 06:33:19 +00:00
|
|
|
if (!DS->isSingleDecl())
|
2009-01-16 23:28:06 +00:00
|
|
|
return StmtError(Diag((*DS->decl_begin())->getLocation(),
|
|
|
|
diag::err_toomany_element_decls));
|
|
|
|
|
2009-03-28 06:33:19 +00:00
|
|
|
Decl *D = DS->getSingleDecl();
|
2008-10-06 20:58:11 +00:00
|
|
|
FirstType = cast<ValueDecl>(D)->getType();
|
2008-11-20 06:38:18 +00:00
|
|
|
// C99 6.8.5p3: The declaration part of a 'for' statement shall only
|
|
|
|
// declare identifiers for objects having storage class 'auto' or
|
|
|
|
// 'register'.
|
2008-04-15 22:42:06 +00:00
|
|
|
VarDecl *VD = cast<VarDecl>(D);
|
|
|
|
if (VD->isBlockVarDecl() && !VD->hasLocalStorage())
|
2009-01-16 23:28:06 +00:00
|
|
|
return StmtError(Diag(VD->getLocation(),
|
|
|
|
diag::err_non_variable_decl_in_for));
|
2008-08-25 18:16:36 +00:00
|
|
|
} else {
|
2009-03-13 17:38:01 +00:00
|
|
|
if (cast<Expr>(First)->isLvalue(Context) != Expr::LV_Valid)
|
2009-01-16 23:28:06 +00:00
|
|
|
return StmtError(Diag(First->getLocStart(),
|
|
|
|
diag::err_selector_element_not_lvalue)
|
|
|
|
<< First->getSourceRange());
|
2008-08-25 18:16:36 +00:00
|
|
|
|
2009-09-09 15:08:12 +00:00
|
|
|
FirstType = static_cast<Expr*>(First)->getType();
|
2008-08-25 18:16:36 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
if (!FirstType->isObjCObjectPointerType() &&
|
2009-08-14 21:53:27 +00:00
|
|
|
!FirstType->isBlockPointerType())
|
2008-11-19 05:27:50 +00:00
|
|
|
Diag(ForLoc, diag::err_selector_element_type)
|
2008-11-24 06:25:27 +00:00
|
|
|
<< FirstType << First->getSourceRange();
|
2008-01-03 17:55:25 +00:00
|
|
|
}
|
|
|
|
if (Second) {
|
|
|
|
DefaultFunctionArrayConversion(Second);
|
|
|
|
QualType SecondType = Second->getType();
|
2009-07-16 15:41:00 +00:00
|
|
|
if (!SecondType->isObjCObjectPointerType())
|
2008-11-19 05:27:50 +00:00
|
|
|
Diag(ForLoc, diag::err_collection_expr_type)
|
2008-11-24 06:25:27 +00:00
|
|
|
<< SecondType << Second->getSourceRange();
|
2008-01-03 17:55:25 +00:00
|
|
|
}
|
2009-01-16 23:28:06 +00:00
|
|
|
first.release();
|
|
|
|
second.release();
|
|
|
|
body.release();
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) ObjCForCollectionStmt(First, Second, Body,
|
|
|
|
ForLoc, RParenLoc));
|
2008-01-03 17:55:25 +00:00
|
|
|
}
|
2006-11-10 05:07:45 +00:00
|
|
|
|
2009-01-18 13:19:59 +00:00
|
|
|
Action::OwningStmtResult
|
2007-09-16 14:56:35 +00:00
|
|
|
Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
|
2006-11-10 05:07:45 +00:00
|
|
|
IdentifierInfo *LabelII) {
|
2008-09-03 18:15:37 +00:00
|
|
|
// If we are in a block, reject all gotos for now.
|
|
|
|
if (CurBlock)
|
2009-01-18 13:19:59 +00:00
|
|
|
return StmtError(Diag(GotoLoc, diag::err_goto_in_block));
|
2008-09-03 18:15:37 +00:00
|
|
|
|
2007-05-28 06:28:18 +00:00
|
|
|
// Look up the record for this label identifier.
|
2009-04-18 20:01:55 +00:00
|
|
|
LabelStmt *&LabelDecl = getLabelMap()[LabelII];
|
2007-05-28 06:28:18 +00:00
|
|
|
|
2009-03-13 15:38:40 +00:00
|
|
|
// If we haven't seen this label yet, create a forward reference.
|
|
|
|
if (LabelDecl == 0)
|
2009-02-07 01:47:29 +00:00
|
|
|
LabelDecl = new (Context) LabelStmt(LabelLoc, LabelII, 0);
|
2009-01-18 13:19:59 +00:00
|
|
|
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) GotoStmt(LabelDecl, GotoLoc, LabelLoc));
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
2007-05-31 06:00:00 +00:00
|
|
|
|
2009-01-18 13:19:59 +00:00
|
|
|
Action::OwningStmtResult
|
2009-04-19 01:04:21 +00:00
|
|
|
Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
|
2009-01-18 13:19:59 +00:00
|
|
|
ExprArg DestExp) {
|
2009-03-26 00:18:06 +00:00
|
|
|
// Convert operand to void*
|
2009-03-26 07:32:37 +00:00
|
|
|
Expr* E = DestExp.takeAs<Expr>();
|
2009-05-16 00:20:29 +00:00
|
|
|
if (!E->isTypeDependent()) {
|
|
|
|
QualType ETy = E->getType();
|
|
|
|
AssignConvertType ConvTy =
|
|
|
|
CheckSingleAssignmentConstraints(Context.VoidPtrTy, E);
|
|
|
|
if (DiagnoseAssignmentResult(ConvTy, StarLoc, Context.VoidPtrTy, ETy,
|
|
|
|
E, "passing"))
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E));
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-18 13:19:59 +00:00
|
|
|
Action::OwningStmtResult
|
2007-09-16 14:56:35 +00:00
|
|
|
Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
|
2006-11-10 05:17:58 +00:00
|
|
|
Scope *S = CurScope->getContinueParent();
|
|
|
|
if (!S) {
|
|
|
|
// C99 6.8.6.2p1: A break shall appear only in or as a loop body.
|
2009-01-18 13:19:59 +00:00
|
|
|
return StmtError(Diag(ContinueLoc, diag::err_continue_not_in_loop));
|
2006-11-10 05:17:58 +00:00
|
|
|
}
|
2009-01-18 13:19:59 +00:00
|
|
|
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) ContinueStmt(ContinueLoc));
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-18 13:19:59 +00:00
|
|
|
Action::OwningStmtResult
|
2007-09-16 14:56:35 +00:00
|
|
|
Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
|
2006-11-10 05:17:58 +00:00
|
|
|
Scope *S = CurScope->getBreakParent();
|
|
|
|
if (!S) {
|
|
|
|
// C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body.
|
2009-01-18 13:19:59 +00:00
|
|
|
return StmtError(Diag(BreakLoc, diag::err_break_not_in_loop_or_switch));
|
2006-11-10 05:17:58 +00:00
|
|
|
}
|
2009-01-18 13:19:59 +00:00
|
|
|
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) BreakStmt(BreakLoc));
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
|
|
|
|
2008-10-29 00:13:59 +00:00
|
|
|
/// ActOnBlockReturnStmt - Utility routine to figure out block's return type.
|
2008-09-03 18:15:37 +00:00
|
|
|
///
|
2009-01-18 13:19:59 +00:00
|
|
|
Action::OwningStmtResult
|
2008-09-03 18:15:37 +00:00
|
|
|
Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
|
|
|
|
// If this is the first return we've seen in the block, infer the type of
|
|
|
|
// the block from it.
|
2009-06-19 23:37:08 +00:00
|
|
|
if (CurBlock->ReturnType.isNull()) {
|
2008-09-16 22:25:10 +00:00
|
|
|
if (RetValExp) {
|
2008-09-24 22:26:48 +00:00
|
|
|
// Don't call UsualUnaryConversions(), since we don't want to do
|
|
|
|
// integer promotions here.
|
|
|
|
DefaultFunctionArrayConversion(RetValExp);
|
2009-06-19 23:37:08 +00:00
|
|
|
CurBlock->ReturnType = RetValExp->getType();
|
|
|
|
if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) {
|
|
|
|
// We have to remove a 'const' added to copied-in variable which was
|
|
|
|
// part of the implementation spec. and not the actual qualifier for
|
|
|
|
// the variable.
|
|
|
|
if (CDRE->isConstQualAdded())
|
|
|
|
CurBlock->ReturnType.removeConst();
|
|
|
|
}
|
2008-09-16 22:25:10 +00:00
|
|
|
} else
|
2009-06-19 23:37:08 +00:00
|
|
|
CurBlock->ReturnType = Context.VoidTy;
|
2008-09-03 18:15:37 +00:00
|
|
|
}
|
2009-06-19 23:37:08 +00:00
|
|
|
QualType FnRetType = CurBlock->ReturnType;
|
2009-01-18 13:19:59 +00:00
|
|
|
|
2009-06-30 02:34:44 +00:00
|
|
|
if (CurBlock->TheDecl->hasAttr<NoReturnAttr>()) {
|
2009-04-29 21:40:37 +00:00
|
|
|
Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr)
|
|
|
|
<< getCurFunctionOrMethodDecl()->getDeclName();
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
2008-09-03 18:15:37 +00:00
|
|
|
// Otherwise, verify that this result type matches the previous one. We are
|
|
|
|
// pickier with blocks than for normal functions because we don't have GCC
|
|
|
|
// compatibility to worry about here.
|
|
|
|
if (CurBlock->ReturnType->isVoidType()) {
|
|
|
|
if (RetValExp) {
|
|
|
|
Diag(ReturnLoc, diag::err_return_block_has_expr);
|
2009-02-07 01:47:29 +00:00
|
|
|
RetValExp->Destroy(Context);
|
2008-09-03 18:15:37 +00:00
|
|
|
RetValExp = 0;
|
|
|
|
}
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
|
2008-09-03 18:15:37 +00:00
|
|
|
}
|
2009-01-18 13:19:59 +00:00
|
|
|
|
|
|
|
if (!RetValExp)
|
|
|
|
return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
|
|
|
|
|
2009-02-04 22:31:32 +00:00
|
|
|
if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
|
|
|
|
// we have a non-void block with an expression, continue checking
|
|
|
|
QualType RetValType = RetValExp->getType();
|
|
|
|
|
2009-09-09 15:08:12 +00:00
|
|
|
// 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
|
2009-02-04 22:31:32 +00:00
|
|
|
// function return.
|
2009-01-18 13:19:59 +00:00
|
|
|
|
2009-02-04 22:31:32 +00:00
|
|
|
// In C++ the return statement is handled via a copy initialization.
|
|
|
|
// the C version of which boils down to CheckSingleAssignmentConstraints.
|
|
|
|
// FIXME: Leaks RetValExp.
|
|
|
|
if (PerformCopyInitialization(RetValExp, FnRetType, "returning"))
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
|
|
|
|
}
|
2009-01-18 13:19:59 +00:00
|
|
|
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
|
2008-09-03 18:15:37 +00:00
|
|
|
}
|
2006-11-10 05:07:45 +00:00
|
|
|
|
2009-04-12 17:16:29 +00:00
|
|
|
/// IsReturnCopyElidable - Whether returning @p RetExpr from a function that
|
|
|
|
/// returns a @p RetType fulfills the criteria for copy elision (C++0x 12.8p15).
|
|
|
|
static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType,
|
|
|
|
Expr *RetExpr) {
|
|
|
|
QualType ExprType = RetExpr->getType();
|
|
|
|
// - in a return statement in a function with ...
|
|
|
|
// ... a class return type ...
|
|
|
|
if (!RetType->isRecordType())
|
|
|
|
return false;
|
|
|
|
// ... the same cv-unqualified type as the function return type ...
|
First part of changes to eliminate problems with cv-qualifiers and
sugared types. The basic problem is that our qualifier accessors
(getQualifiers, getCVRQualifiers, isConstQualified, etc.) only look at
the current QualType and not at any qualifiers that come from sugared
types, meaning that we won't see these qualifiers through, e.g.,
typedefs:
typedef const int CInt;
typedef CInt Self;
Self.isConstQualified() currently returns false!
Various bugs (e.g., PR5383) have cropped up all over the front end due
to such problems. I'm addressing this problem by splitting each
qualifier accessor into two versions:
- the "local" version only returns qualifiers on this particular
QualType instance
- the "normal" version that will eventually combine qualifiers from this
QualType instance with the qualifiers on the canonical type to
produce the full set of qualifiers.
This commit adds the local versions and switches a few callers from
the "normal" version (e.g., isConstQualified) over to the "local"
version (e.g., isLocalConstQualified) when that is the right thing to
do, e.g., because we're printing or serializing the qualifiers. Also,
switch a bunch of
Context.getCanonicalType(T1).getUnqualifiedType() == Context.getCanonicalType(T2).getQualifiedType()
expressions over to
Context.hasSameUnqualifiedType(T1, T2)
llvm-svn: 88969
2009-11-16 21:35:15 +00:00
|
|
|
if (!Ctx.hasSameUnqualifiedType(RetType, ExprType))
|
2009-04-12 17:16:29 +00:00
|
|
|
return false;
|
|
|
|
// ... the expression is the name of a non-volatile automatic object ...
|
|
|
|
// We ignore parentheses here.
|
|
|
|
// FIXME: Is this compliant?
|
|
|
|
const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens());
|
|
|
|
if (!DR)
|
|
|
|
return false;
|
|
|
|
const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
|
|
|
|
if (!VD)
|
|
|
|
return false;
|
|
|
|
return VD->hasLocalStorage() && !VD->getType()->isReferenceType()
|
|
|
|
&& !VD->getType().isVolatileQualified();
|
|
|
|
}
|
|
|
|
|
2009-01-18 13:19:59 +00:00
|
|
|
Action::OwningStmtResult
|
2009-08-18 16:11:00 +00:00
|
|
|
Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
|
|
|
|
Expr *RetValExp = rex.takeAs<Expr>();
|
2008-09-03 18:15:37 +00:00
|
|
|
if (CurBlock)
|
|
|
|
return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
|
2009-01-18 13:19:59 +00:00
|
|
|
|
2008-12-04 23:50:19 +00:00
|
|
|
QualType FnRetType;
|
2009-04-29 00:43:21 +00:00
|
|
|
if (const FunctionDecl *FD = getCurFunctionDecl()) {
|
2008-12-04 23:50:19 +00:00
|
|
|
FnRetType = FD->getResultType();
|
2009-06-30 02:34:44 +00:00
|
|
|
if (FD->hasAttr<NoReturnAttr>())
|
2009-05-31 19:32:13 +00:00
|
|
|
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
|
2009-04-29 00:43:21 +00:00
|
|
|
<< getCurFunctionOrMethodDecl()->getDeclName();
|
|
|
|
} else if (ObjCMethodDecl *MD = getCurMethodDecl())
|
2009-03-03 00:45:38 +00:00
|
|
|
FnRetType = MD->getResultType();
|
|
|
|
else // If we don't have a function/method context, bail.
|
|
|
|
return StmtError();
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2008-01-04 18:04:52 +00:00
|
|
|
if (FnRetType->isVoidType()) {
|
2009-10-01 23:25:31 +00:00
|
|
|
if (RetValExp && !RetValExp->isTypeDependent()) {
|
|
|
|
// C99 6.8.6.4p1 (ext_ since GCC warns)
|
2008-12-18 02:01:17 +00:00
|
|
|
unsigned D = diag::ext_return_has_expr;
|
|
|
|
if (RetValExp->getType()->isVoidType())
|
|
|
|
D = diag::ext_return_has_void_expr;
|
2009-01-18 13:19:59 +00:00
|
|
|
|
2008-12-18 02:03:48 +00:00
|
|
|
// return (some void expression); is legal in C++.
|
|
|
|
if (D != diag::ext_return_has_void_expr ||
|
|
|
|
!getLangOptions().CPlusPlus) {
|
|
|
|
NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
|
|
|
|
Diag(ReturnLoc, D)
|
|
|
|
<< CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl)
|
|
|
|
<< RetValExp->getSourceRange();
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-08-18 16:11:00 +00:00
|
|
|
RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true);
|
2007-05-29 14:23:36 +00:00
|
|
|
}
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
|
2007-05-27 23:58:33 +00:00
|
|
|
}
|
2009-01-18 13:19:59 +00:00
|
|
|
|
2009-05-15 00:48:27 +00:00
|
|
|
if (!RetValExp && !FnRetType->isDependentType()) {
|
2008-11-19 08:23:25 +00:00
|
|
|
unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4
|
|
|
|
// C99 6.8.6.4p1 (ext_ since GCC warns)
|
|
|
|
if (getLangOptions().C99) DiagID = diag::ext_return_missing_expr;
|
|
|
|
|
|
|
|
if (FunctionDecl *FD = getCurFunctionDecl())
|
2008-11-23 21:45:46 +00:00
|
|
|
Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/;
|
2008-11-19 08:23:25 +00:00
|
|
|
else
|
2008-11-23 21:45:46 +00:00
|
|
|
Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) ReturnStmt(ReturnLoc, (Expr*)0));
|
2008-11-19 08:23:25 +00:00
|
|
|
}
|
2009-01-18 13:19:59 +00:00
|
|
|
|
2008-12-05 23:32:09 +00:00
|
|
|
if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
|
|
|
|
// we have a non-void function with an expression, continue checking
|
2009-01-18 13:19:59 +00:00
|
|
|
|
2009-09-09 15:08:12 +00:00
|
|
|
// 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
|
2009-01-18 13:19:59 +00:00
|
|
|
// function return.
|
|
|
|
|
2009-04-12 17:16:29 +00:00
|
|
|
// C++0x 12.8p15: When certain criteria are met, an implementation is
|
|
|
|
// allowed to omit the copy construction of a class object, [...]
|
|
|
|
// - in a return statement in a function with a class return type, when
|
|
|
|
// the expression is the name of a non-volatile automatic object with
|
|
|
|
// the same cv-unqualified type as the function return type, the copy
|
|
|
|
// operation can be omitted [...]
|
|
|
|
// C++0x 12.8p16: When the criteria for elision of a copy operation are met
|
|
|
|
// and the object to be copied is designated by an lvalue, overload
|
|
|
|
// resolution to select the constructor for the copy is first performed
|
|
|
|
// as if the object were designated by an rvalue.
|
|
|
|
// Note that we only compute Elidable if we're in C++0x, since we don't
|
|
|
|
// care otherwise.
|
|
|
|
bool Elidable = getLangOptions().CPlusPlus0x ?
|
|
|
|
IsReturnCopyElidable(Context, FnRetType, RetValExp) :
|
|
|
|
false;
|
|
|
|
|
2008-12-05 23:32:09 +00:00
|
|
|
// In C++ the return statement is handled via a copy initialization.
|
2009-01-18 13:19:59 +00:00
|
|
|
// the C version of which boils down to CheckSingleAssignmentConstraints.
|
2009-04-12 17:16:29 +00:00
|
|
|
// FIXME: Leaks RetValExp on error.
|
2009-11-14 01:20:54 +00:00
|
|
|
if (PerformCopyInitialization(RetValExp, FnRetType, "returning", Elidable)){
|
|
|
|
// We should still clean up our temporaries, even when we're failing!
|
|
|
|
RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true);
|
2009-01-18 13:19:59 +00:00
|
|
|
return StmtError();
|
2009-11-14 01:20:54 +00:00
|
|
|
}
|
|
|
|
|
2008-12-05 23:32:09 +00:00
|
|
|
if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
|
|
|
|
}
|
|
|
|
|
2009-08-18 16:11:00 +00:00
|
|
|
if (RetValExp)
|
|
|
|
RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true);
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
|
2006-11-10 05:07:45 +00:00
|
|
|
}
|
|
|
|
|
2009-03-13 17:38:01 +00:00
|
|
|
/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
|
|
|
|
/// ignore "noop" casts in places where an lvalue is required by an inline asm.
|
|
|
|
/// We emulate this behavior when -fheinous-gnu-extensions is specified, but
|
|
|
|
/// provide a strong guidance to not use it.
|
|
|
|
///
|
|
|
|
/// This method checks to see if the argument is an acceptable l-value and
|
|
|
|
/// returns false if it is a case we can handle.
|
|
|
|
static bool CheckAsmLValue(const Expr *E, Sema &S) {
|
|
|
|
if (E->isLvalue(S.Context) == Expr::LV_Valid)
|
|
|
|
return false; // Cool, this is an lvalue.
|
|
|
|
|
|
|
|
// Okay, this is not an lvalue, but perhaps it is the result of a cast that we
|
|
|
|
// are supposed to allow.
|
|
|
|
const Expr *E2 = E->IgnoreParenNoopCasts(S.Context);
|
|
|
|
if (E != E2 && E2->isLvalue(S.Context) == Expr::LV_Valid) {
|
|
|
|
if (!S.getLangOptions().HeinousExtensions)
|
|
|
|
S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
|
|
|
|
<< E->getSourceRange();
|
|
|
|
else
|
|
|
|
S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
|
|
|
|
<< E->getSourceRange();
|
|
|
|
// Accept, even if we emitted an error diagnostic.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// None of the above, just randomly invalid non-lvalue.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-18 16:53:17 +00:00
|
|
|
Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
|
|
|
|
bool IsSimple,
|
|
|
|
bool IsVolatile,
|
|
|
|
unsigned NumOutputs,
|
|
|
|
unsigned NumInputs,
|
|
|
|
std::string *Names,
|
|
|
|
MultiExprArg constraints,
|
|
|
|
MultiExprArg exprs,
|
|
|
|
ExprArg asmString,
|
|
|
|
MultiExprArg clobbers,
|
|
|
|
SourceLocation RParenLoc) {
|
|
|
|
unsigned NumClobbers = clobbers.size();
|
|
|
|
StringLiteral **Constraints =
|
|
|
|
reinterpret_cast<StringLiteral**>(constraints.get());
|
|
|
|
Expr **Exprs = reinterpret_cast<Expr **>(exprs.get());
|
|
|
|
StringLiteral *AsmString = cast<StringLiteral>((Expr *)asmString.get());
|
|
|
|
StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get());
|
|
|
|
|
2009-01-27 20:38:24 +00:00
|
|
|
llvm::SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2008-08-18 19:55:17 +00:00
|
|
|
// The parser verifies that there is a string literal here.
|
2008-07-23 06:46:56 +00:00
|
|
|
if (AsmString->isWide())
|
2009-01-18 16:53:17 +00:00
|
|
|
return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character)
|
|
|
|
<< AsmString->getSourceRange());
|
|
|
|
|
2008-08-18 19:55:17 +00:00
|
|
|
for (unsigned i = 0; i != NumOutputs; i++) {
|
|
|
|
StringLiteral *Literal = Constraints[i];
|
2008-07-23 06:46:56 +00:00
|
|
|
if (Literal->isWide())
|
2009-01-18 16:53:17 +00:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
|
|
|
|
<< Literal->getSourceRange());
|
|
|
|
|
2009-09-09 15:08:12 +00:00
|
|
|
TargetInfo::ConstraintInfo Info(Literal->getStrData(),
|
2009-04-26 17:57:12 +00:00
|
|
|
Literal->getByteLength(),
|
|
|
|
Names[i]);
|
2009-04-26 17:19:08 +00:00
|
|
|
if (!Context.Target.validateOutputConstraint(Info))
|
2009-01-18 16:53:17 +00:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),
|
2009-04-26 17:19:08 +00:00
|
|
|
diag::err_asm_invalid_output_constraint)
|
|
|
|
<< Info.getConstraintStr());
|
2009-01-18 16:53:17 +00:00
|
|
|
|
2007-11-27 04:11:28 +00:00
|
|
|
// Check that the output exprs are valid lvalues.
|
2009-05-03 07:49:42 +00:00
|
|
|
Expr *OutputExpr = Exprs[i];
|
2009-03-13 17:38:01 +00:00
|
|
|
if (CheckAsmLValue(OutputExpr, *this)) {
|
2009-05-03 07:49:42 +00:00
|
|
|
return StmtError(Diag(OutputExpr->getLocStart(),
|
2008-11-19 05:27:50 +00:00
|
|
|
diag::err_asm_invalid_lvalue_in_output)
|
2009-05-03 07:49:42 +00:00
|
|
|
<< OutputExpr->getSourceRange());
|
2007-11-23 19:43:50 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-04-26 07:16:29 +00:00
|
|
|
OutputConstraintInfos.push_back(Info);
|
2007-11-23 19:43:50 +00:00
|
|
|
}
|
2009-01-18 16:53:17 +00:00
|
|
|
|
2009-05-03 05:55:43 +00:00
|
|
|
llvm::SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
|
|
|
|
|
2007-11-23 19:43:50 +00:00
|
|
|
for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
|
2008-08-18 19:55:17 +00:00
|
|
|
StringLiteral *Literal = Constraints[i];
|
2008-07-23 06:46:56 +00:00
|
|
|
if (Literal->isWide())
|
2009-01-18 16:53:17 +00:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
|
|
|
|
<< Literal->getSourceRange());
|
|
|
|
|
2009-09-09 15:08:12 +00:00
|
|
|
TargetInfo::ConstraintInfo Info(Literal->getStrData(),
|
2009-04-26 17:57:12 +00:00
|
|
|
Literal->getByteLength(),
|
|
|
|
Names[i]);
|
2009-05-21 09:52:38 +00:00
|
|
|
if (!Context.Target.validateInputConstraint(OutputConstraintInfos.data(),
|
2009-04-26 17:57:12 +00:00
|
|
|
NumOutputs, Info)) {
|
2009-01-18 16:53:17 +00:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),
|
2009-04-26 17:19:08 +00:00
|
|
|
diag::err_asm_invalid_input_constraint)
|
|
|
|
<< Info.getConstraintStr());
|
2007-11-27 04:11:28 +00:00
|
|
|
}
|
2009-01-18 16:53:17 +00:00
|
|
|
|
2009-05-03 07:49:42 +00:00
|
|
|
Expr *InputExpr = Exprs[i];
|
2009-01-18 16:53:17 +00:00
|
|
|
|
2009-01-20 20:49:22 +00:00
|
|
|
// Only allow void types for memory constraints.
|
2009-04-26 07:16:29 +00:00
|
|
|
if (Info.allowsMemory() && !Info.allowsRegister()) {
|
2009-03-13 17:38:01 +00:00
|
|
|
if (CheckAsmLValue(InputExpr, *this))
|
2009-05-03 07:49:42 +00:00
|
|
|
return StmtError(Diag(InputExpr->getLocStart(),
|
2009-01-20 20:49:22 +00:00
|
|
|
diag::err_asm_invalid_lvalue_in_input)
|
2009-04-26 17:19:08 +00:00
|
|
|
<< Info.getConstraintStr()
|
2009-05-03 07:49:42 +00:00
|
|
|
<< InputExpr->getSourceRange());
|
2007-11-23 19:43:50 +00:00
|
|
|
}
|
2009-01-18 16:53:17 +00:00
|
|
|
|
2009-04-26 07:16:29 +00:00
|
|
|
if (Info.allowsRegister()) {
|
2009-01-20 20:49:22 +00:00
|
|
|
if (InputExpr->getType()->isVoidType()) {
|
2009-05-03 07:49:42 +00:00
|
|
|
return StmtError(Diag(InputExpr->getLocStart(),
|
2009-01-20 20:49:22 +00:00
|
|
|
diag::err_asm_invalid_type_in_input)
|
2009-09-09 15:08:12 +00:00
|
|
|
<< InputExpr->getType() << Info.getConstraintStr()
|
2009-05-03 07:49:42 +00:00
|
|
|
<< InputExpr->getSourceRange());
|
2009-01-20 20:49:22 +00:00
|
|
|
}
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-02-22 02:11:23 +00:00
|
|
|
DefaultFunctionArrayConversion(Exprs[i]);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-03 05:55:43 +00:00
|
|
|
InputConstraintInfos.push_back(Info);
|
2007-11-23 19:43:50 +00:00
|
|
|
}
|
2009-01-18 16:53:17 +00:00
|
|
|
|
2007-11-25 00:25:21 +00:00
|
|
|
// Check that the clobbers are valid.
|
2008-08-18 19:55:17 +00:00
|
|
|
for (unsigned i = 0; i != NumClobbers; i++) {
|
|
|
|
StringLiteral *Literal = Clobbers[i];
|
2008-07-23 06:46:56 +00:00
|
|
|
if (Literal->isWide())
|
2009-01-18 16:53:17 +00:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
|
|
|
|
<< Literal->getSourceRange());
|
|
|
|
|
2009-08-19 20:04:03 +00:00
|
|
|
std::string Clobber(Literal->getStrData(),
|
|
|
|
Literal->getStrData() +
|
|
|
|
Literal->getByteLength());
|
2009-01-18 16:53:17 +00:00
|
|
|
|
2008-07-23 06:46:56 +00:00
|
|
|
if (!Context.Target.isValidGCCRegisterName(Clobber.c_str()))
|
2009-01-18 16:53:17 +00:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),
|
2009-08-19 20:04:03 +00:00
|
|
|
diag::err_asm_unknown_register_name) << Clobber);
|
2007-11-25 00:25:21 +00:00
|
|
|
}
|
2009-01-18 16:53:17 +00:00
|
|
|
|
|
|
|
constraints.release();
|
|
|
|
exprs.release();
|
|
|
|
asmString.release();
|
|
|
|
clobbers.release();
|
2009-03-10 23:41:04 +00:00
|
|
|
AsmStmt *NS =
|
|
|
|
new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs,
|
|
|
|
Names, Constraints, Exprs, AsmString, NumClobbers,
|
|
|
|
Clobbers, RParenLoc);
|
|
|
|
// Validate the asm string, ensuring it makes sense given the operands we
|
|
|
|
// have.
|
|
|
|
llvm::SmallVector<AsmStmt::AsmStringPiece, 8> Pieces;
|
|
|
|
unsigned DiagOffs;
|
|
|
|
if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) {
|
2009-03-10 23:57:07 +00:00
|
|
|
Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
|
|
|
|
<< AsmString->getSourceRange();
|
2009-03-10 23:41:04 +00:00
|
|
|
DeleteStmt(NS);
|
|
|
|
return StmtError();
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-03 05:55:43 +00:00
|
|
|
// Validate tied input operands for type mismatches.
|
|
|
|
for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) {
|
|
|
|
TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-03 05:55:43 +00:00
|
|
|
// If this is a tied constraint, verify that the output and input have
|
|
|
|
// either exactly the same type, or that they are int/ptr operands with the
|
|
|
|
// same size (int/long, int*/long, are ok etc).
|
|
|
|
if (!Info.hasTiedOperand()) continue;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-03 05:55:43 +00:00
|
|
|
unsigned TiedTo = Info.getTiedOperand();
|
2009-05-03 07:04:21 +00:00
|
|
|
Expr *OutputExpr = Exprs[TiedTo];
|
2009-05-03 06:50:40 +00:00
|
|
|
Expr *InputExpr = Exprs[i+NumOutputs];
|
2009-05-03 05:59:17 +00:00
|
|
|
QualType InTy = InputExpr->getType();
|
|
|
|
QualType OutTy = OutputExpr->getType();
|
|
|
|
if (Context.hasSameType(InTy, OutTy))
|
2009-05-03 05:55:43 +00:00
|
|
|
continue; // All types can be tied to themselves.
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-03 05:59:17 +00:00
|
|
|
// Int/ptr operands have some special cases that we allow.
|
|
|
|
if ((OutTy->isIntegerType() || OutTy->isPointerType()) &&
|
|
|
|
(InTy->isIntegerType() || InTy->isPointerType())) {
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-03 05:59:17 +00:00
|
|
|
// They are ok if they are the same size. Tying void* to int is ok if
|
|
|
|
// they are the same size, for example. This also allows tying void* to
|
|
|
|
// int*.
|
2009-05-03 08:32:32 +00:00
|
|
|
uint64_t OutSize = Context.getTypeSize(OutTy);
|
|
|
|
uint64_t InSize = Context.getTypeSize(InTy);
|
|
|
|
if (OutSize == InSize)
|
2009-05-03 05:55:43 +00:00
|
|
|
continue;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-03 08:32:32 +00:00
|
|
|
// If the smaller input/output operand is not mentioned in the asm string,
|
|
|
|
// then we can promote it and the asm string won't notice. Check this
|
2009-05-03 07:04:21 +00:00
|
|
|
// case now.
|
2009-05-03 08:32:32 +00:00
|
|
|
bool SmallerValueMentioned = false;
|
2009-05-03 08:24:16 +00:00
|
|
|
for (unsigned p = 0, e = Pieces.size(); p != e; ++p) {
|
|
|
|
AsmStmt::AsmStringPiece &Piece = Pieces[p];
|
|
|
|
if (!Piece.isOperand()) continue;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-03 08:32:32 +00:00
|
|
|
// If this is a reference to the input and if the input was the smaller
|
|
|
|
// one, then we have to reject this asm.
|
|
|
|
if (Piece.getOperandNo() == i+NumOutputs) {
|
|
|
|
if (InSize < OutSize) {
|
|
|
|
SmallerValueMentioned = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this is a reference to the input and if the input was the smaller
|
|
|
|
// one, then we have to reject this asm.
|
|
|
|
if (Piece.getOperandNo() == TiedTo) {
|
|
|
|
if (InSize > OutSize) {
|
|
|
|
SmallerValueMentioned = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-05-03 07:04:21 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-03 08:32:32 +00:00
|
|
|
// If the smaller value wasn't mentioned in the asm string, and if the
|
|
|
|
// output was a register, just extend the shorter one to the size of the
|
|
|
|
// larger one.
|
|
|
|
if (!SmallerValueMentioned &&
|
2009-05-03 07:04:21 +00:00
|
|
|
OutputConstraintInfos[TiedTo].allowsRegister())
|
|
|
|
continue;
|
2009-05-03 05:55:43 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-05-03 06:50:40 +00:00
|
|
|
Diag(InputExpr->getLocStart(),
|
2009-05-03 05:55:43 +00:00
|
|
|
diag::err_asm_tying_incompatible_types)
|
2009-05-03 05:59:17 +00:00
|
|
|
<< InTy << OutTy << OutputExpr->getSourceRange()
|
2009-05-03 05:55:43 +00:00
|
|
|
<< InputExpr->getSourceRange();
|
|
|
|
DeleteStmt(NS);
|
|
|
|
return StmtError();
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-10 23:41:04 +00:00
|
|
|
return Owned(NS);
|
2007-10-29 04:04:16 +00:00
|
|
|
}
|
2007-11-01 23:59:59 +00:00
|
|
|
|
2009-01-18 17:43:11 +00:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
|
2009-03-28 19:18:32 +00:00
|
|
|
SourceLocation RParen, DeclPtrTy Parm,
|
2009-01-18 17:43:11 +00:00
|
|
|
StmtArg Body, StmtArg catchList) {
|
2009-05-01 19:30:39 +00:00
|
|
|
Stmt *CatchList = catchList.takeAs<Stmt>();
|
2009-03-28 19:18:32 +00:00
|
|
|
ParmVarDecl *PVD = cast_or_null<ParmVarDecl>(Parm.getAs<Decl>());
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-03 20:59:06 +00:00
|
|
|
// PVD == 0 implies @catch(...).
|
2009-03-03 21:16:54 +00:00
|
|
|
if (PVD) {
|
2009-04-12 23:26:56 +00:00
|
|
|
// If we already know the decl is invalid, reject it.
|
|
|
|
if (PVD->isInvalidDecl())
|
|
|
|
return StmtError();
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-16 15:41:00 +00:00
|
|
|
if (!PVD->getType()->isObjCObjectPointerType())
|
2009-09-09 15:08:12 +00:00
|
|
|
return StmtError(Diag(PVD->getLocation(),
|
2009-03-03 21:16:54 +00:00
|
|
|
diag::err_catch_param_not_objc_type));
|
|
|
|
if (PVD->getType()->isObjCQualifiedIdType())
|
2009-09-09 15:08:12 +00:00
|
|
|
return StmtError(Diag(PVD->getLocation(),
|
2009-03-03 23:13:51 +00:00
|
|
|
diag::err_illegal_qualifiers_on_catch_parm));
|
2009-03-03 21:16:54 +00:00
|
|
|
}
|
2009-04-12 23:26:56 +00:00
|
|
|
|
2009-02-07 01:47:29 +00:00
|
|
|
ObjCAtCatchStmt *CS = new (Context) ObjCAtCatchStmt(AtLoc, RParen,
|
2009-05-01 19:49:17 +00:00
|
|
|
PVD, Body.takeAs<Stmt>(), CatchList);
|
2009-01-18 17:43:11 +00:00
|
|
|
return Owned(CatchList ? CatchList : CS);
|
2007-11-01 23:59:59 +00:00
|
|
|
}
|
|
|
|
|
2009-01-18 17:43:11 +00:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) {
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) ObjCAtFinallyStmt(AtLoc,
|
|
|
|
static_cast<Stmt*>(Body.release())));
|
2007-11-02 00:18:53 +00:00
|
|
|
}
|
2007-11-02 15:39:31 +00:00
|
|
|
|
2009-01-18 17:43:11 +00:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc,
|
|
|
|
StmtArg Try, StmtArg Catch, StmtArg Finally) {
|
2009-04-19 05:21:20 +00:00
|
|
|
CurFunctionNeedsScopeChecking = true;
|
2009-05-01 19:49:17 +00:00
|
|
|
return Owned(new (Context) ObjCAtTryStmt(AtLoc, Try.takeAs<Stmt>(),
|
|
|
|
Catch.takeAs<Stmt>(),
|
|
|
|
Finally.takeAs<Stmt>()));
|
2007-11-02 15:39:31 +00:00
|
|
|
}
|
|
|
|
|
2009-01-18 17:43:11 +00:00
|
|
|
Action::OwningStmtResult
|
2009-02-12 15:54:59 +00:00
|
|
|
Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) {
|
2009-05-01 19:30:39 +00:00
|
|
|
Expr *ThrowExpr = expr.takeAs<Expr>();
|
2009-02-11 17:45:08 +00:00
|
|
|
if (!ThrowExpr) {
|
2009-02-11 20:05:44 +00:00
|
|
|
// @throw without an expression designates a rethrow (which much occur
|
|
|
|
// in the context of an @catch clause).
|
|
|
|
Scope *AtCatchParent = CurScope;
|
|
|
|
while (AtCatchParent && !AtCatchParent->isAtCatchScope())
|
|
|
|
AtCatchParent = AtCatchParent->getParent();
|
|
|
|
if (!AtCatchParent)
|
2009-02-12 18:09:32 +00:00
|
|
|
return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch));
|
2009-02-11 17:45:08 +00:00
|
|
|
} else {
|
|
|
|
QualType ThrowType = ThrowExpr->getType();
|
|
|
|
// Make sure the expression type is an ObjC pointer or "void *".
|
2009-07-16 15:41:00 +00:00
|
|
|
if (!ThrowType->isObjCObjectPointerType()) {
|
2009-07-29 21:53:49 +00:00
|
|
|
const PointerType *PT = ThrowType->getAs<PointerType>();
|
2009-02-11 17:45:08 +00:00
|
|
|
if (!PT || !PT->getPointeeType()->isVoidType())
|
2009-02-12 18:09:32 +00:00
|
|
|
return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object)
|
|
|
|
<< ThrowExpr->getType() << ThrowExpr->getSourceRange());
|
2009-02-11 17:45:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowExpr));
|
2007-11-07 02:00:49 +00:00
|
|
|
}
|
2007-11-02 15:39:31 +00:00
|
|
|
|
2009-01-18 17:43:11 +00:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr,
|
|
|
|
StmtArg SynchBody) {
|
2009-04-21 06:01:00 +00:00
|
|
|
CurFunctionNeedsScopeChecking = true;
|
|
|
|
|
2009-04-21 06:11:25 +00:00
|
|
|
// Make sure the expression type is an ObjC pointer or "void *".
|
|
|
|
Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get());
|
2009-07-16 15:41:00 +00:00
|
|
|
if (!SyncExpr->getType()->isObjCObjectPointerType()) {
|
2009-07-29 21:53:49 +00:00
|
|
|
const PointerType *PT = SyncExpr->getType()->getAs<PointerType>();
|
2009-04-21 06:11:25 +00:00
|
|
|
if (!PT || !PT->getPointeeType()->isVoidType())
|
|
|
|
return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object)
|
|
|
|
<< SyncExpr->getType() << SyncExpr->getSourceRange());
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
|
|
|
return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc,
|
2009-05-01 19:49:17 +00:00
|
|
|
SynchExpr.takeAs<Stmt>(),
|
|
|
|
SynchBody.takeAs<Stmt>()));
|
2008-01-29 19:14:59 +00:00
|
|
|
}
|
2008-12-22 19:15:10 +00:00
|
|
|
|
|
|
|
/// ActOnCXXCatchBlock - Takes an exception declaration and a handler block
|
|
|
|
/// and creates a proper catch handler from them.
|
|
|
|
Action::OwningStmtResult
|
2009-03-28 19:18:32 +00:00
|
|
|
Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, DeclPtrTy ExDecl,
|
2008-12-22 19:15:10 +00:00
|
|
|
StmtArg HandlerBlock) {
|
|
|
|
// There's nothing to test that ActOnExceptionDecl didn't already test.
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) CXXCatchStmt(CatchLoc,
|
2009-03-28 19:18:32 +00:00
|
|
|
cast_or_null<VarDecl>(ExDecl.getAs<Decl>()),
|
2009-05-01 19:49:17 +00:00
|
|
|
HandlerBlock.takeAs<Stmt>()));
|
2008-12-22 19:15:10 +00:00
|
|
|
}
|
2008-12-22 21:35:02 +00:00
|
|
|
|
2009-07-29 17:15:45 +00:00
|
|
|
class TypeWithHandler {
|
|
|
|
QualType t;
|
|
|
|
CXXCatchStmt *stmt;
|
|
|
|
public:
|
|
|
|
TypeWithHandler(const QualType &type, CXXCatchStmt *statement)
|
|
|
|
: t(type), stmt(statement) {}
|
|
|
|
|
2009-09-24 19:53:00 +00:00
|
|
|
// An arbitrary order is fine as long as it places identical
|
|
|
|
// types next to each other.
|
2009-07-29 17:15:45 +00:00
|
|
|
bool operator<(const TypeWithHandler &y) const {
|
2009-09-24 19:53:00 +00:00
|
|
|
if (t.getAsOpaquePtr() < y.t.getAsOpaquePtr())
|
2009-07-29 17:15:45 +00:00
|
|
|
return true;
|
2009-09-24 19:53:00 +00:00
|
|
|
if (t.getAsOpaquePtr() > y.t.getAsOpaquePtr())
|
2009-07-29 17:15:45 +00:00
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return getTypeSpecStartLoc() < y.getTypeSpecStartLoc();
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-29 17:15:45 +00:00
|
|
|
bool operator==(const TypeWithHandler& other) const {
|
2009-09-24 19:53:00 +00:00
|
|
|
return t == other.t;
|
2009-07-29 17:15:45 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-29 17:15:45 +00:00
|
|
|
QualType getQualType() const { return t; }
|
|
|
|
CXXCatchStmt *getCatchStmt() const { return stmt; }
|
|
|
|
SourceLocation getTypeSpecStartLoc() const {
|
|
|
|
return stmt->getExceptionDecl()->getTypeSpecStartLoc();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-12-22 21:35:02 +00:00
|
|
|
/// ActOnCXXTryBlock - Takes a try compound-statement and a number of
|
|
|
|
/// handlers and creates a try statement from them.
|
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock,
|
|
|
|
MultiStmtArg RawHandlers) {
|
|
|
|
unsigned NumHandlers = RawHandlers.size();
|
|
|
|
assert(NumHandlers > 0 &&
|
|
|
|
"The parser shouldn't call this if there are no handlers.");
|
|
|
|
Stmt **Handlers = reinterpret_cast<Stmt**>(RawHandlers.get());
|
|
|
|
|
2009-07-29 17:15:45 +00:00
|
|
|
llvm::SmallVector<TypeWithHandler, 8> TypesWithHandlers;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
|
|
|
for (unsigned i = 0; i < NumHandlers; ++i) {
|
2008-12-22 21:35:02 +00:00
|
|
|
CXXCatchStmt *Handler = llvm::cast<CXXCatchStmt>(Handlers[i]);
|
2009-07-29 17:15:45 +00:00
|
|
|
if (!Handler->getExceptionDecl()) {
|
|
|
|
if (i < NumHandlers - 1)
|
|
|
|
return StmtError(Diag(Handler->getLocStart(),
|
|
|
|
diag::err_early_catch_all));
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-29 17:15:45 +00:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-29 17:15:45 +00:00
|
|
|
const QualType CaughtType = Handler->getCaughtType();
|
|
|
|
const QualType CanonicalCaughtType = Context.getCanonicalType(CaughtType);
|
|
|
|
TypesWithHandlers.push_back(TypeWithHandler(CanonicalCaughtType, Handler));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Detect handlers for the same type as an earlier one.
|
|
|
|
if (NumHandlers > 1) {
|
|
|
|
llvm::array_pod_sort(TypesWithHandlers.begin(), TypesWithHandlers.end());
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-29 17:15:45 +00:00
|
|
|
TypeWithHandler prev = TypesWithHandlers[0];
|
|
|
|
for (unsigned i = 1; i < TypesWithHandlers.size(); ++i) {
|
|
|
|
TypeWithHandler curr = TypesWithHandlers[i];
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-29 17:15:45 +00:00
|
|
|
if (curr == prev) {
|
|
|
|
Diag(curr.getTypeSpecStartLoc(),
|
|
|
|
diag::warn_exception_caught_by_earlier_handler)
|
|
|
|
<< curr.getCatchStmt()->getCaughtType().getAsString();
|
|
|
|
Diag(prev.getTypeSpecStartLoc(),
|
|
|
|
diag::note_previous_exception_handler)
|
|
|
|
<< prev.getCatchStmt()->getCaughtType().getAsString();
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-29 17:15:45 +00:00
|
|
|
prev = curr;
|
|
|
|
}
|
2008-12-22 21:35:02 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2008-12-22 21:35:02 +00:00
|
|
|
// FIXME: We should detect handlers that cannot catch anything because an
|
|
|
|
// earlier handler catches a superclass. Need to find a method that is not
|
|
|
|
// quadratic for this.
|
|
|
|
// Neither of these are explicitly forbidden, but every compiler detects them
|
|
|
|
// and warns.
|
|
|
|
|
2009-04-27 20:27:31 +00:00
|
|
|
CurFunctionNeedsScopeChecking = true;
|
2008-12-22 21:35:02 +00:00
|
|
|
RawHandlers.release();
|
2009-02-07 01:47:29 +00:00
|
|
|
return Owned(new (Context) CXXTryStmt(TryLoc,
|
|
|
|
static_cast<Stmt*>(TryBlock.release()),
|
|
|
|
Handlers, NumHandlers));
|
2008-12-22 21:35:02 +00:00
|
|
|
}
|