2006-11-10 13:07:45 +08:00
|
|
|
//===--- SemaStmt.cpp - Semantic Analysis for Statements ------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2006-11-10 13:07:45 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements semantic analysis for statements.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Sema.h"
|
Switch the initialization required by return statements over to the
new InitializationSequence. This fixes some bugs (e.g., PR5808),
changed some diagnostics, and caused more churn than expected. What's
new:
- InitializationSequence now has a "C conversion sequence" category
and step kind, which falls back to
- Changed the diagnostics for returns to always have the result type
of the function first and the type of the expression second.
CheckSingleAssignmentConstraints to peform checking in C.
- Improved ASTs for initialization of return values. The ASTs now
capture all of the temporaries we need to create, but
intentionally do not bind the tempoary that is actually returned,
so that it won't get destroyed twice.
- Make sure to perform an (elidable!) copy of the class object that
is returned from a class.
- Fix copy elision in CodeGen to properly see through the
subexpressions that occur with elidable copies.
- Give "new" its own entity kind; as with return values and thrown
objects, we don't bind the expression so we don't call a
destructor for it.
Note that, with this patch, I've broken returning move-only types in
C++0x. We'll fix it later, when we tackle NRVO.
llvm-svn: 91669
2009-12-18 13:02:21 +08:00
|
|
|
#include "SemaInit.h"
|
2008-11-23 05:04:56 +08:00
|
|
|
#include "clang/AST/APValue.h"
|
2007-08-23 13:46:52 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2008-08-11 13:35:13 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2009-11-23 21:46:08 +08:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2009-08-17 00:57:27 +08:00
|
|
|
#include "clang/AST/ExprObjC.h"
|
2009-04-26 09:32:48 +08:00
|
|
|
#include "clang/AST/StmtObjC.h"
|
|
|
|
#include "clang/AST/StmtCXX.h"
|
2010-04-07 06:24:14 +08:00
|
|
|
#include "clang/AST/TypeLoc.h"
|
2009-11-23 21:46:08 +08:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2007-11-25 08:25:21 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2009-07-30 01:15:45 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2006-11-10 13:07:45 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2009-05-18 05:11:30 +08:00
|
|
|
Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) {
|
|
|
|
Expr *E = expr->takeAs<Expr>();
|
2007-09-16 22:56:35 +08:00
|
|
|
assert(E && "ActOnExprStmt(): missing expression");
|
2009-09-03 08:43:07 +08: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-26 07:18:17 +08: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 20:04:03 +08:00
|
|
|
|
2008-07-26 07:18:17 +08:00
|
|
|
// Same thing in for stmt first clause (when expr) and third clause.
|
2008-12-21 20:04:03 +08:00
|
|
|
return Owned(static_cast<Stmt*>(E));
|
2007-06-27 13:38:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-21 20:04:03 +08:00
|
|
|
Sema::OwningStmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc) {
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) NullStmt(SemiLoc));
|
2007-05-28 09:45:28 +08:00
|
|
|
}
|
|
|
|
|
2009-03-30 00:50:03 +08:00
|
|
|
Sema::OwningStmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg,
|
2008-12-21 20:04:03 +08:00
|
|
|
SourceLocation StartLoc,
|
|
|
|
SourceLocation EndLoc) {
|
2009-04-13 04:13:14 +08:00
|
|
|
DeclGroupRef DG = dg.getAsVal<DeclGroupRef>();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-30 00:50:03 +08:00
|
|
|
// If we have an invalid decl, just return an error.
|
2009-04-13 04:13:14 +08:00
|
|
|
if (DG.isNull()) return StmtError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
return Owned(new (Context) DeclStmt(DG, StartLoc, EndLoc));
|
2007-05-30 06:59:26 +08:00
|
|
|
}
|
2006-11-10 13:07:45 +08:00
|
|
|
|
2009-11-20 06:12:37 +08: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-31 06:17:18 +08:00
|
|
|
void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
|
2009-07-31 06:39:03 +08:00
|
|
|
const Expr *E = dyn_cast_or_null<Expr>(S);
|
2009-07-31 06:17:18 +08:00
|
|
|
if (!E)
|
|
|
|
return;
|
|
|
|
|
|
|
|
SourceLocation Loc;
|
|
|
|
SourceRange R1, R2;
|
2009-11-04 07:25:48 +08:00
|
|
|
if (!E->isUnusedResultAWarning(Loc, R1, R2, Context))
|
2009-07-31 06:17:18 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-17 00:57:27 +08: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-21 01:02:02 +08:00
|
|
|
if (isa<ObjCImplicitSetterGetterRefExpr>(E))
|
2009-08-17 00:57:27 +08:00
|
|
|
DiagID = diag::warn_unused_property_expr;
|
2009-10-13 12:53:48 +08:00
|
|
|
|
2010-02-12 06:55:30 +08:00
|
|
|
if (const CXXExprWithTemporaries *Temps = dyn_cast<CXXExprWithTemporaries>(E))
|
|
|
|
E = Temps->getSubExpr();
|
|
|
|
if (const CXXZeroInitValueExpr *Zero = dyn_cast<CXXZeroInitValueExpr>(E)) {
|
|
|
|
if (const RecordType *RecordT = Zero->getType()->getAs<RecordType>())
|
|
|
|
if (CXXRecordDecl *RecordD = dyn_cast<CXXRecordDecl>(RecordT->getDecl()))
|
|
|
|
if (!RecordD->hasTrivialDestructor())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-10-13 12:53:48 +08:00
|
|
|
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
|
2010-03-12 15:11:26 +08:00
|
|
|
if (E->getType()->isVoidType())
|
|
|
|
return;
|
|
|
|
|
2009-10-13 12:53:48 +08:00
|
|
|
// If the callee has attribute pure, const, or warn_unused_result, warn with
|
|
|
|
// a more specific message to make it clear what is happening.
|
2009-12-21 07:11:08 +08:00
|
|
|
if (const Decl *FD = CE->getCalleeDecl()) {
|
2009-10-13 12:53:48 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-03-31 02:22:15 +08:00
|
|
|
else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
|
|
|
|
const ObjCMethodDecl *MD = ME->getMethodDecl();
|
|
|
|
if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
|
|
|
|
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
|
|
|
|
return;
|
|
|
|
}
|
2010-04-17 06:09:46 +08:00
|
|
|
} else if (const CXXFunctionalCastExpr *FC
|
|
|
|
= dyn_cast<CXXFunctionalCastExpr>(E)) {
|
|
|
|
if (isa<CXXConstructExpr>(FC->getSubExpr()) ||
|
|
|
|
isa<CXXTemporaryObjectExpr>(FC->getSubExpr()))
|
|
|
|
return;
|
2010-03-31 02:22:15 +08:00
|
|
|
}
|
2010-04-07 06:24:14 +08:00
|
|
|
// Diagnose "(void*) blah" as a typo for "(void) blah".
|
|
|
|
else if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E)) {
|
|
|
|
TypeSourceInfo *TI = CE->getTypeInfoAsWritten();
|
|
|
|
QualType T = TI->getType();
|
|
|
|
|
|
|
|
// We really do want to use the non-canonical type here.
|
|
|
|
if (T == Context.VoidPtrTy) {
|
|
|
|
PointerTypeLoc TL = cast<PointerTypeLoc>(TI->getTypeLoc());
|
|
|
|
|
|
|
|
Diag(Loc, diag::warn_unused_voidptr)
|
|
|
|
<< FixItHint::CreateRemoval(TL.getStarLoc());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-17 00:57:27 +08:00
|
|
|
Diag(Loc, DiagID) << R1 << R2;
|
2009-07-31 06:17:18 +08:00
|
|
|
}
|
|
|
|
|
2008-12-21 20:04:03 +08:00
|
|
|
Action::OwningStmtResult
|
2007-09-16 22:56:35 +08:00
|
|
|
Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
|
2008-12-21 20:04:03 +08:00
|
|
|
MultiStmtArg elts, bool isStmtExpr) {
|
|
|
|
unsigned NumElts = elts.size();
|
|
|
|
Stmt **Elts = reinterpret_cast<Stmt**>(elts.release());
|
2007-08-27 12:29:41 +08: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 23:08:12 +08:00
|
|
|
|
2007-08-27 12:29:41 +08:00
|
|
|
if (i != NumElts) {
|
2009-01-20 09:17:11 +08:00
|
|
|
Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin();
|
2007-08-27 12:29:41 +08:00
|
|
|
Diag(D->getLocation(), diag::ext_mixed_decls_code);
|
|
|
|
}
|
|
|
|
}
|
2007-09-01 05:49:55 +08:00
|
|
|
// Warn about unused expressions in statements.
|
|
|
|
for (unsigned i = 0; i != NumElts; ++i) {
|
2009-07-31 06:17:18 +08:00
|
|
|
// Ignore statements that are last in a statement expression.
|
|
|
|
if (isStmtExpr && i == NumElts - 1)
|
2007-09-01 05:49:55 +08:00
|
|
|
continue;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-31 06:17:18 +08:00
|
|
|
DiagnoseUnusedExprResult(Elts[i]);
|
2007-09-01 05:49:55 +08:00
|
|
|
}
|
2008-12-21 20:04:03 +08:00
|
|
|
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) CompoundStmt(Context, Elts, NumElts, L, R));
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2008-12-29 00:13:43 +08:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprArg lhsval,
|
|
|
|
SourceLocation DotDotDotLoc, ExprArg rhsval,
|
2009-03-04 12:23:07 +08:00
|
|
|
SourceLocation ColonLoc) {
|
2008-12-29 00:13:43 +08:00
|
|
|
assert((lhsval.get() != 0) && "missing expression in case statement");
|
|
|
|
|
2007-05-09 05:09:37 +08:00
|
|
|
// C99 6.8.4.2p3: The expression shall be an integer constant.
|
2009-09-09 23:08:12 +08:00
|
|
|
// However, GCC allows any evaluatable integer expression.
|
2008-12-29 00:13:43 +08:00
|
|
|
Expr *LHSVal = static_cast<Expr*>(lhsval.get());
|
2009-09-09 23:08:12 +08:00
|
|
|
if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() &&
|
2009-05-16 07:57:33 +08:00
|
|
|
VerifyIntegerConstantExpression(LHSVal))
|
2009-03-04 12:23:07 +08:00
|
|
|
return StmtError();
|
2007-05-09 05:09:37 +08:00
|
|
|
|
2007-07-18 10:28:47 +08:00
|
|
|
// GCC extension: The expression shall be an integer constant.
|
2008-12-29 00:13:43 +08:00
|
|
|
|
|
|
|
Expr *RHSVal = static_cast<Expr*>(rhsval.get());
|
2009-05-16 07:57:33 +08:00
|
|
|
if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() &&
|
|
|
|
VerifyIntegerConstantExpression(RHSVal)) {
|
2007-08-23 13:46:52 +08:00
|
|
|
RHSVal = 0; // Recover by just forgetting about it.
|
2008-12-29 00:13:43 +08:00
|
|
|
rhsval = 0;
|
|
|
|
}
|
|
|
|
|
2009-04-19 04:10:59 +08:00
|
|
|
if (getSwitchStack().empty()) {
|
2007-07-24 01:05:23 +08:00
|
|
|
Diag(CaseLoc, diag::err_case_not_in_switch);
|
2009-03-04 12:23:07 +08:00
|
|
|
return StmtError();
|
2007-07-24 01:05:23 +08:00
|
|
|
}
|
2007-06-03 09:44:43 +08:00
|
|
|
|
2008-12-29 00:13:43 +08:00
|
|
|
// Only now release the smart pointers.
|
|
|
|
lhsval.release();
|
|
|
|
rhsval.release();
|
2009-05-16 07:57:33 +08:00
|
|
|
CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc,
|
|
|
|
ColonLoc);
|
2009-04-19 04:10:59 +08:00
|
|
|
getSwitchStack().back()->addSwitchCase(CS);
|
2008-12-29 00:13:43 +08:00
|
|
|
return Owned(CS);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2009-03-04 12:23:07 +08: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-02 03:30:39 +08:00
|
|
|
Stmt *SubStmt = subStmt.takeAs<Stmt>();
|
2009-03-04 12:23:07 +08:00
|
|
|
CS->setSubStmt(SubStmt);
|
|
|
|
}
|
|
|
|
|
2008-12-29 00:13:43 +08:00
|
|
|
Action::OwningStmtResult
|
2009-09-09 23:08:12 +08:00
|
|
|
Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
|
2008-12-29 00:13:43 +08:00
|
|
|
StmtArg subStmt, Scope *CurScope) {
|
2009-05-02 03:30:39 +08:00
|
|
|
Stmt *SubStmt = subStmt.takeAs<Stmt>();
|
2008-12-29 00:13:43 +08:00
|
|
|
|
2009-04-19 04:10:59 +08:00
|
|
|
if (getSwitchStack().empty()) {
|
2007-07-21 11:00:26 +08:00
|
|
|
Diag(DefaultLoc, diag::err_default_not_in_switch);
|
2008-12-29 00:13:43 +08:00
|
|
|
return Owned(SubStmt);
|
2007-07-21 11:00:26 +08:00
|
|
|
}
|
2008-12-29 00:13:43 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
DefaultStmt *DS = new (Context) DefaultStmt(DefaultLoc, ColonLoc, SubStmt);
|
2009-04-19 04:10:59 +08:00
|
|
|
getSwitchStack().back()->addSwitchCase(DS);
|
2008-12-29 00:13:43 +08:00
|
|
|
return Owned(DS);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2009-01-11 08:38:46 +08:00
|
|
|
Action::OwningStmtResult
|
2007-09-16 22:56:35 +08:00
|
|
|
Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
|
2009-01-11 08:38:46 +08:00
|
|
|
SourceLocation ColonLoc, StmtArg subStmt) {
|
2009-05-02 03:30:39 +08:00
|
|
|
Stmt *SubStmt = subStmt.takeAs<Stmt>();
|
2007-05-28 14:28:18 +08:00
|
|
|
// Look up the record for this label identifier.
|
2009-04-19 04:01:55 +08:00
|
|
|
LabelStmt *&LabelDecl = getLabelMap()[II];
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2007-05-28 14:28:18 +08:00
|
|
|
// If not forward referenced or defined already, just create a new LabelStmt.
|
2009-03-13 23:38:40 +08:00
|
|
|
if (LabelDecl == 0)
|
|
|
|
return Owned(LabelDecl = new (Context) LabelStmt(IdentLoc, II, SubStmt));
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2007-05-28 14:56:27 +08:00
|
|
|
assert(LabelDecl->getID() == II && "Label mismatch!");
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2007-05-28 14:28:18 +08:00
|
|
|
// Otherwise, this label was either forward reference or multiply defined. If
|
|
|
|
// multiply defined, reject it now.
|
|
|
|
if (LabelDecl->getSubStmt()) {
|
2008-11-24 05:45:46 +08:00
|
|
|
Diag(IdentLoc, diag::err_redefinition_of_label) << LabelDecl->getID();
|
2008-11-24 07:12:31 +08:00
|
|
|
Diag(LabelDecl->getIdentLoc(), diag::note_previous_definition);
|
2009-01-11 08:38:46 +08:00
|
|
|
return Owned(SubStmt);
|
2007-05-28 14:28:18 +08:00
|
|
|
}
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2007-05-28 14:28:18 +08: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 11:00:26 +08:00
|
|
|
LabelDecl->setSubStmt(SubStmt);
|
2009-01-11 08:38:46 +08:00
|
|
|
return Owned(LabelDecl);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2009-01-11 08:38:46 +08:00
|
|
|
Action::OwningStmtResult
|
2009-11-25 08:27:52 +08:00
|
|
|
Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar,
|
2009-01-11 08:38:46 +08:00
|
|
|
StmtArg ThenVal, SourceLocation ElseLoc,
|
|
|
|
StmtArg ElseVal) {
|
2009-05-18 02:26:53 +08:00
|
|
|
OwningExprResult CondResult(CondVal.release());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-24 07:44:04 +08:00
|
|
|
VarDecl *ConditionVar = 0;
|
2009-11-25 08:27:52 +08:00
|
|
|
if (CondVar.get()) {
|
|
|
|
ConditionVar = CondVar.getAs<VarDecl>();
|
|
|
|
CondResult = CheckConditionVariable(ConditionVar);
|
|
|
|
if (CondResult.isInvalid())
|
|
|
|
return StmtError();
|
2009-11-24 07:44:04 +08:00
|
|
|
}
|
2009-11-25 08:27:52 +08:00
|
|
|
Expr *ConditionExpr = CondResult.takeAs<Expr>();
|
|
|
|
if (!ConditionExpr)
|
|
|
|
return StmtError();
|
2009-11-24 07:44:04 +08:00
|
|
|
|
2009-11-25 08:27:52 +08:00
|
|
|
if (CheckBooleanCondition(ConditionExpr, IfLoc)) {
|
|
|
|
CondResult = ConditionExpr;
|
2009-10-13 05:59:07 +08:00
|
|
|
return StmtError();
|
2009-05-16 02:53:42 +08:00
|
|
|
}
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2009-05-02 03:49:17 +08:00
|
|
|
Stmt *thenStmt = ThenVal.takeAs<Stmt>();
|
2009-07-31 06:39:03 +08:00
|
|
|
DiagnoseUnusedExprResult(thenStmt);
|
2007-05-29 10:14:17 +08:00
|
|
|
|
2007-10-11 04:50:11 +08: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 23:08:12 +08:00
|
|
|
if (!ElseVal.get()) {
|
2007-10-11 04:50:11 +08:00
|
|
|
if (NullStmt* stmt = dyn_cast<NullStmt>(thenStmt))
|
|
|
|
Diag(stmt->getSemiLoc(), diag::warn_empty_if_body);
|
|
|
|
}
|
|
|
|
|
2009-07-31 06:39:03 +08:00
|
|
|
Stmt *elseStmt = ElseVal.takeAs<Stmt>();
|
|
|
|
DiagnoseUnusedExprResult(elseStmt);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-18 02:26:53 +08:00
|
|
|
CondResult.release();
|
2009-11-25 08:27:52 +08:00
|
|
|
return Owned(new (Context) IfStmt(IfLoc, ConditionVar, ConditionExpr,
|
|
|
|
thenStmt, ElseLoc, elseStmt));
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
2007-05-29 10:14:17 +08:00
|
|
|
|
2009-01-11 08:38:46 +08:00
|
|
|
Action::OwningStmtResult
|
2009-11-25 08:27:52 +08:00
|
|
|
Sema::ActOnStartOfSwitchStmt(FullExprArg cond, DeclPtrTy CondVar) {
|
|
|
|
OwningExprResult CondResult(cond.release());
|
|
|
|
|
2009-11-25 01:07:59 +08:00
|
|
|
VarDecl *ConditionVar = 0;
|
2009-11-25 08:27:52 +08:00
|
|
|
if (CondVar.get()) {
|
|
|
|
ConditionVar = CondVar.getAs<VarDecl>();
|
|
|
|
CondResult = CheckConditionVariable(ConditionVar);
|
|
|
|
if (CondResult.isInvalid())
|
|
|
|
return StmtError();
|
2009-11-25 01:07:59 +08:00
|
|
|
}
|
2009-11-25 14:20:02 +08:00
|
|
|
SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar,
|
|
|
|
CondResult.takeAs<Expr>());
|
2009-04-19 04:10:59 +08:00
|
|
|
getSwitchStack().push_back(SS);
|
2009-01-11 08:38:46 +08:00
|
|
|
return Owned(SS);
|
2007-07-22 15:07:56 +08:00
|
|
|
}
|
2007-07-18 10:28:47 +08:00
|
|
|
|
2007-08-23 13:46:52 +08: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 23:08:12 +08:00
|
|
|
SourceLocation Loc,
|
2007-08-23 13:46:52 +08: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.
|
|
|
|
Val.extend(NewWidth);
|
|
|
|
Val.setIsSigned(NewSign);
|
2010-03-01 09:04:55 +08:00
|
|
|
|
|
|
|
// If the input was signed and negative and the output is
|
|
|
|
// unsigned, don't bother to warn: this is implementation-defined
|
|
|
|
// behavior.
|
|
|
|
// FIXME: Introduce a second, default-ignored warning for this case?
|
2007-08-23 13:46:52 +08:00
|
|
|
} else if (NewWidth < Val.getBitWidth()) {
|
|
|
|
// If this is a truncation, check for overflow.
|
|
|
|
llvm::APSInt ConvVal(Val);
|
|
|
|
ConvVal.trunc(NewWidth);
|
2007-08-24 06:08:35 +08:00
|
|
|
ConvVal.setIsSigned(NewSign);
|
2007-08-23 13:46:52 +08:00
|
|
|
ConvVal.extend(Val.getBitWidth());
|
2007-08-24 06:08:35 +08:00
|
|
|
ConvVal.setIsSigned(Val.isSigned());
|
2007-08-23 13:46:52 +08:00
|
|
|
if (ConvVal != Val)
|
2008-11-20 14:06:08 +08:00
|
|
|
Diag(Loc, DiagID) << Val.toString(10) << ConvVal.toString(10);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
// Regardless of whether a diagnostic was emitted, really do the
|
|
|
|
// truncation.
|
|
|
|
Val.trunc(NewWidth);
|
2007-08-24 06:08:35 +08:00
|
|
|
Val.setIsSigned(NewSign);
|
2007-08-23 13:46:52 +08:00
|
|
|
} else if (NewSign != Val.isSigned()) {
|
|
|
|
// Convert the sign to match the sign of the condition. This can cause
|
|
|
|
// overflow as well: unsigned(INTMIN)
|
2010-02-18 08:56:01 +08:00
|
|
|
// We don't diagnose this overflow, because it is implementation-defined
|
|
|
|
// behavior.
|
|
|
|
// FIXME: Introduce a second, default-ignored warning for this case?
|
2007-08-23 13:46:52 +08:00
|
|
|
llvm::APSInt OldVal(Val);
|
|
|
|
Val.setIsSigned(NewSign);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-24 02:29:20 +08:00
|
|
|
namespace {
|
|
|
|
struct CaseCompareFunctor {
|
|
|
|
bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
|
|
|
|
const llvm::APSInt &RHS) {
|
|
|
|
return LHS.first < RHS;
|
|
|
|
}
|
2007-09-04 02:31:57 +08:00
|
|
|
bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
|
|
|
|
const std::pair<llvm::APSInt, CaseStmt*> &RHS) {
|
|
|
|
return LHS.first < RHS.first;
|
|
|
|
}
|
2007-08-24 02:29:20 +08:00
|
|
|
bool operator()(const llvm::APSInt &LHS,
|
|
|
|
const std::pair<llvm::APSInt, CaseStmt*> &RHS) {
|
|
|
|
return LHS < RHS.first;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2007-09-22 02:15:22 +08: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;
|
|
|
|
}
|
|
|
|
|
2010-02-09 06:24:16 +08:00
|
|
|
/// CmpEnumVals - Comparison predicate for sorting enumeration values.
|
|
|
|
///
|
|
|
|
static bool CmpEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs,
|
|
|
|
const std::pair<llvm::APSInt, EnumConstantDecl*>& rhs)
|
|
|
|
{
|
|
|
|
return lhs.first < rhs.first;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// EqEnumVals - Comparison preficate for uniqing enumeration values.
|
|
|
|
///
|
|
|
|
static bool EqEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs,
|
|
|
|
const std::pair<llvm::APSInt, EnumConstantDecl*>& rhs)
|
|
|
|
{
|
|
|
|
return lhs.first == rhs.first;
|
|
|
|
}
|
|
|
|
|
2009-10-17 00:45:22 +08: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 12:55:54 +08: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,
|
2010-03-30 07:34:08 +08:00
|
|
|
S.PDiag(diag::err_switch_incomplete_class_type)
|
2009-11-25 12:55:54 +08:00
|
|
|
<< CondExpr->getSourceRange()))
|
|
|
|
return true;
|
|
|
|
|
2010-03-31 05:47:33 +08:00
|
|
|
UnresolvedSet<4> ViableConversions;
|
|
|
|
UnresolvedSet<4> ExplicitConversions;
|
2009-11-25 12:55:54 +08:00
|
|
|
if (const RecordType *RecordTy = CondType->getAs<RecordType>()) {
|
2010-01-20 08:46:10 +08:00
|
|
|
const UnresolvedSetImpl *Conversions
|
2009-11-25 12:55:54 +08:00
|
|
|
= cast<CXXRecordDecl>(RecordTy->getDecl())
|
|
|
|
->getVisibleConversionFunctions();
|
2010-01-20 08:46:10 +08:00
|
|
|
for (UnresolvedSetImpl::iterator I = Conversions->begin(),
|
2009-11-25 12:55:54 +08:00
|
|
|
E = Conversions->end(); I != E; ++I) {
|
2010-03-31 05:47:33 +08:00
|
|
|
if (CXXConversionDecl *Conversion
|
|
|
|
= dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl()))
|
2009-11-25 12:55:54 +08:00
|
|
|
if (Conversion->getConversionType().getNonReferenceType()
|
|
|
|
->isIntegralType()) {
|
|
|
|
if (Conversion->isExplicit())
|
2010-03-31 05:47:33 +08:00
|
|
|
ExplicitConversions.addDecl(I.getDecl(), I.getAccess());
|
2009-11-25 12:55:54 +08:00
|
|
|
else
|
2010-03-31 05:47:33 +08:00
|
|
|
ViableConversions.addDecl(I.getDecl(), I.getAccess());
|
2009-11-25 12:55:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (ViableConversions.size()) {
|
|
|
|
case 0:
|
|
|
|
if (ExplicitConversions.size() == 1) {
|
2010-03-31 05:47:33 +08:00
|
|
|
DeclAccessPair Found = ExplicitConversions[0];
|
|
|
|
CXXConversionDecl *Conversion =
|
|
|
|
cast<CXXConversionDecl>(Found->getUnderlyingDecl());
|
2009-11-25 12:55:54 +08:00
|
|
|
// The user probably meant to invoke the given explicit
|
|
|
|
// conversion; use it.
|
|
|
|
QualType ConvTy
|
2010-03-31 05:47:33 +08:00
|
|
|
= Conversion->getConversionType().getNonReferenceType();
|
2009-11-25 12:55:54 +08:00
|
|
|
std::string TypeStr;
|
|
|
|
ConvTy.getAsStringInternal(TypeStr, S.Context.PrintingPolicy);
|
|
|
|
|
|
|
|
S.Diag(SwitchLoc, diag::err_switch_explicit_conversion)
|
|
|
|
<< CondType << ConvTy << CondExpr->getSourceRange()
|
2010-04-01 01:46:05 +08:00
|
|
|
<< FixItHint::CreateInsertion(CondExpr->getLocStart(),
|
|
|
|
"static_cast<" + TypeStr + ">(")
|
|
|
|
<< FixItHint::CreateInsertion(
|
2009-11-25 12:55:54 +08:00
|
|
|
S.PP.getLocForEndOfToken(CondExpr->getLocEnd()),
|
|
|
|
")");
|
2010-03-31 05:47:33 +08:00
|
|
|
S.Diag(Conversion->getLocation(), diag::note_switch_conversion)
|
2009-11-25 12:55:54 +08:00
|
|
|
<< ConvTy->isEnumeralType() << ConvTy;
|
|
|
|
|
|
|
|
// If we aren't in a SFINAE context, build a call to the
|
|
|
|
// explicit conversion function.
|
|
|
|
if (S.isSFINAEContext())
|
|
|
|
return true;
|
|
|
|
|
2010-03-31 05:47:33 +08:00
|
|
|
S.CheckMemberOperatorAccess(CondExpr->getExprLoc(),
|
|
|
|
CondExpr, 0, Found);
|
|
|
|
CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found, Conversion);
|
2009-11-25 12:55:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// We'll complain below about a non-integral condition type.
|
|
|
|
break;
|
|
|
|
|
2010-03-31 05:47:33 +08:00
|
|
|
case 1: {
|
2009-11-25 12:55:54 +08:00
|
|
|
// Apply this conversion.
|
2010-03-31 05:47:33 +08:00
|
|
|
DeclAccessPair Found = ViableConversions[0];
|
|
|
|
S.CheckMemberOperatorAccess(CondExpr->getExprLoc(),
|
|
|
|
CondExpr, 0, Found);
|
|
|
|
CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found,
|
|
|
|
cast<CXXConversionDecl>(Found->getUnderlyingDecl()));
|
2009-11-25 12:55:54 +08:00
|
|
|
break;
|
2010-03-31 05:47:33 +08:00
|
|
|
}
|
2009-11-25 12:55:54 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
S.Diag(SwitchLoc, diag::err_switch_multiple_conversions)
|
|
|
|
<< CondType << CondExpr->getSourceRange();
|
|
|
|
for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
|
2010-03-31 05:47:33 +08:00
|
|
|
CXXConversionDecl *Conv
|
|
|
|
= cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());
|
|
|
|
QualType ConvTy = Conv->getConversionType().getNonReferenceType();
|
|
|
|
S.Diag(Conv->getLocation(), diag::note_switch_conversion)
|
2009-11-25 12:55:54 +08:00
|
|
|
<< ConvTy->isEnumeralType() << ConvTy;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-01-24 09:50:29 +08:00
|
|
|
/// ActOnSwitchBodyError - This is called if there is an error parsing the
|
|
|
|
/// body of the switch stmt instead of ActOnFinishSwitchStmt.
|
|
|
|
void Sema::ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch,
|
|
|
|
StmtArg Body) {
|
|
|
|
// Keep the switch stack balanced.
|
|
|
|
assert(getSwitchStack().back() == (SwitchStmt*)Switch.get() &&
|
|
|
|
"switch stack missing push/pop!");
|
|
|
|
getSwitchStack().pop_back();
|
|
|
|
}
|
|
|
|
|
2009-01-11 08:38:46 +08:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
|
|
|
|
StmtArg Body) {
|
2009-05-02 03:49:17 +08:00
|
|
|
Stmt *BodyStmt = Body.takeAs<Stmt>();
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2009-04-19 04:10:59 +08:00
|
|
|
SwitchStmt *SS = getSwitchStack().back();
|
2009-01-11 08:38:46 +08:00
|
|
|
assert(SS == (SwitchStmt*)Switch.get() && "switch stack missing push/pop!");
|
|
|
|
|
2007-09-02 05:08:38 +08:00
|
|
|
SS->setBody(BodyStmt, SwitchLoc);
|
2009-09-09 23:08:12 +08:00
|
|
|
getSwitchStack().pop_back();
|
2007-07-22 15:07:56 +08:00
|
|
|
|
2009-11-25 14:20:02 +08:00
|
|
|
if (SS->getCond() == 0) {
|
|
|
|
SS->Destroy(Context);
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
Expr *CondExpr = SS->getCond();
|
2009-11-23 21:46:08 +08:00
|
|
|
QualType CondTypeBeforePromotion =
|
|
|
|
GetTypeBeforeIntegralPromotion(CondExpr);
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2009-11-25 23:17:36 +08:00
|
|
|
if (getLangOptions().CPlusPlus &&
|
2009-11-25 13:02:21 +08:00
|
|
|
CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr))
|
2009-11-25 23:17:36 +08:00
|
|
|
return StmtError();
|
2009-11-25 13:02:21 +08:00
|
|
|
|
2009-11-25 23:17:36 +08:00
|
|
|
// C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
|
|
|
|
UsualUnaryConversions(CondExpr);
|
2009-11-25 13:02:21 +08:00
|
|
|
QualType CondType = CondExpr->getType();
|
2009-11-23 21:46:08 +08:00
|
|
|
SS->setCond(CondExpr);
|
|
|
|
|
2009-10-17 00:45:22 +08: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-18 03:32:54 +08: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();
|
|
|
|
}
|
|
|
|
|
2010-04-17 07:34:13 +08:00
|
|
|
if (CondExpr->isKnownToHaveBooleanValue()) {
|
2009-10-18 03:32:54 +08:00
|
|
|
// 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 15:07:56 +08:00
|
|
|
}
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2007-08-23 13:46:52 +08: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 23:08:12 +08:00
|
|
|
bool HasDependentValue
|
2009-05-16 07:57:33 +08:00
|
|
|
= CondExpr->isTypeDependent() || CondExpr->isValueDependent();
|
2009-09-09 23:08:12 +08:00
|
|
|
unsigned CondWidth
|
2009-05-16 07:57:33 +08:00
|
|
|
= HasDependentValue? 0
|
2009-10-17 00:45:22 +08:00
|
|
|
: static_cast<unsigned>(Context.getTypeSize(CondTypeBeforePromotion));
|
|
|
|
bool CondIsSigned = CondTypeBeforePromotion->isSignedIntegerType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 13:46:52 +08: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-24 02:29:20 +08:00
|
|
|
typedef llvm::SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy;
|
|
|
|
CaseValsTy CaseVals;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
// Keep track of any GNU case ranges we see. The APSInt is the low value.
|
2010-02-09 06:24:16 +08:00
|
|
|
typedef std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRangesTy;
|
|
|
|
CaseRangesTy CaseRanges;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
DefaultStmt *TheDefaultStmt = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 14:23:56 +08:00
|
|
|
bool CaseListIsErroneous = false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
for (SwitchCase *SC = SS->getSwitchCaseList(); SC && !HasDependentValue;
|
2007-07-22 15:07:56 +08:00
|
|
|
SC = SC->getNextSwitchCase()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-07-22 15:07:56 +08:00
|
|
|
if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC)) {
|
2007-08-23 13:46:52 +08:00
|
|
|
if (TheDefaultStmt) {
|
|
|
|
Diag(DS->getDefaultLoc(), diag::err_multiple_default_labels_defined);
|
2008-11-24 07:12:31 +08:00
|
|
|
Diag(TheDefaultStmt->getDefaultLoc(), diag::note_duplicate_case_prev);
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
// FIXME: Remove the default statement from the switch block so that
|
2009-05-16 15:39:55 +08: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 14:23:56 +08:00
|
|
|
CaseListIsErroneous = true;
|
2007-07-22 15:07:56 +08:00
|
|
|
}
|
2007-08-23 13:46:52 +08:00
|
|
|
TheDefaultStmt = DS;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
} else {
|
|
|
|
CaseStmt *CS = cast<CaseStmt>(SC);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
// We already verified that the expression has a i-c-e value (C99
|
|
|
|
// 6.8.4.2p3) - get that value now.
|
2008-01-17 03:17:22 +08:00
|
|
|
Expr *Lo = CS->getLHS();
|
2009-05-16 07:57:33 +08:00
|
|
|
|
|
|
|
if (Lo->isTypeDependent() || Lo->isValueDependent()) {
|
|
|
|
HasDependentValue = true;
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-23 05:04:56 +08:00
|
|
|
llvm::APSInt LoVal = Lo->EvaluateAsInt(Context);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 13:46:52 +08: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 10:28:47 +08:00
|
|
|
|
2008-01-17 03:17:22 +08:00
|
|
|
// If the LHS is not the same type as the condition, insert an implicit
|
|
|
|
// cast.
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(Lo, CondType, CastExpr::CK_IntegralCast);
|
2008-01-17 03:17:22 +08:00
|
|
|
CS->setLHS(Lo);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 14:23:56 +08:00
|
|
|
// If this is a case range, remember it in CaseRanges, otherwise CaseVals.
|
2009-05-16 07:57:33 +08:00
|
|
|
if (CS->getRHS()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
if (CS->getRHS()->isTypeDependent() ||
|
2009-05-16 07:57:33 +08:00
|
|
|
CS->getRHS()->isValueDependent()) {
|
|
|
|
HasDependentValue = true;
|
|
|
|
break;
|
|
|
|
}
|
2007-08-23 13:46:52 +08:00
|
|
|
CaseRanges.push_back(std::make_pair(LoVal, CS));
|
2009-09-09 23:08:12 +08:00
|
|
|
} else
|
2007-08-23 14:23:56 +08:00
|
|
|
CaseVals.push_back(std::make_pair(LoVal, CS));
|
2007-08-23 13:46:52 +08:00
|
|
|
}
|
|
|
|
}
|
2007-08-23 14:23:56 +08:00
|
|
|
|
2009-05-16 07:57:33 +08: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 23:08:12 +08:00
|
|
|
Diag(CaseVals[i].second->getLHS()->getLocStart(),
|
2009-05-16 07:57:33 +08:00
|
|
|
diag::note_duplicate_case_prev);
|
2009-05-16 15:39:55 +08: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-16 07:57:33 +08:00
|
|
|
CaseListIsErroneous = true;
|
|
|
|
}
|
2007-08-24 01:48:14 +08:00
|
|
|
}
|
2007-08-23 14:23:56 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08: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 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08: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 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08: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 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
// If the LHS is not the same type as the condition, insert an implicit
|
|
|
|
// cast.
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(Hi, CondType, CastExpr::CK_IntegralCast);
|
2009-05-16 07:57:33 +08:00
|
|
|
CR->setRHS(Hi);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08: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-24 02:29:20 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08: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 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
// Check to see whether the case range overlaps with any
|
|
|
|
// singleton cases.
|
|
|
|
CaseStmt *OverlapStmt = 0;
|
|
|
|
llvm::APSInt OverlapVal(32);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08: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 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08: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 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08: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 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
if (OverlapStmt) {
|
|
|
|
// If we have a duplicate, report it.
|
|
|
|
Diag(CR->getLHS()->getLocStart(), diag::err_duplicate_case)
|
|
|
|
<< OverlapVal.toString(10);
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(OverlapStmt->getLHS()->getLocStart(),
|
2009-05-16 07:57:33 +08:00
|
|
|
diag::note_duplicate_case_prev);
|
2009-05-16 15:39:55 +08: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-16 07:57:33 +08:00
|
|
|
CaseListIsErroneous = true;
|
|
|
|
}
|
2007-08-24 02:29:20 +08:00
|
|
|
}
|
2007-08-23 14:23:56 +08:00
|
|
|
}
|
2010-02-09 06:24:16 +08:00
|
|
|
|
|
|
|
// Check to see if switch is over an Enum and handles all of its
|
|
|
|
// values
|
2010-02-18 07:29:11 +08:00
|
|
|
const EnumType* ET = CondTypeBeforePromotion->getAs<EnumType>();
|
2010-02-09 06:24:16 +08:00
|
|
|
// If switch has default case, then ignore it.
|
|
|
|
if (!CaseListIsErroneous && !TheDefaultStmt && ET) {
|
|
|
|
const EnumDecl *ED = ET->getDecl();
|
|
|
|
typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy;
|
|
|
|
EnumValsTy EnumVals;
|
|
|
|
|
|
|
|
// Gather all enum values, set their type and sort them, allowing easier comparison
|
|
|
|
// with CaseVals.
|
|
|
|
for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(); EDI != ED->enumerator_end(); EDI++) {
|
|
|
|
llvm::APSInt Val = (*EDI)->getInitVal();
|
|
|
|
if(Val.getBitWidth() < CondWidth)
|
|
|
|
Val.extend(CondWidth);
|
|
|
|
Val.setIsSigned(CondIsSigned);
|
|
|
|
EnumVals.push_back(std::make_pair(Val, (*EDI)));
|
|
|
|
}
|
|
|
|
std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
|
|
|
|
EnumValsTy::iterator EIend = std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
|
|
|
|
// See which case values aren't in enum
|
|
|
|
EnumValsTy::const_iterator EI = EnumVals.begin();
|
|
|
|
for (CaseValsTy::const_iterator CI = CaseVals.begin(); CI != CaseVals.end(); CI++) {
|
|
|
|
while (EI != EIend && EI->first < CI->first)
|
|
|
|
EI++;
|
|
|
|
if (EI == EIend || EI->first > CI->first)
|
|
|
|
Diag(CI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
|
|
|
|
}
|
|
|
|
// See which of case ranges aren't in enum
|
|
|
|
EI = EnumVals.begin();
|
|
|
|
for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); RI != CaseRanges.end() && EI != EIend; RI++) {
|
|
|
|
while (EI != EIend && EI->first < RI->first)
|
|
|
|
EI++;
|
|
|
|
|
|
|
|
if (EI == EIend || EI->first != RI->first) {
|
|
|
|
Diag(RI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
|
|
|
|
while (EI != EIend && EI->first < Hi)
|
|
|
|
EI++;
|
|
|
|
if (EI == EIend || EI->first != Hi)
|
|
|
|
Diag(RI->second->getRHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
|
|
|
|
}
|
|
|
|
//Check which enum vals aren't in switch
|
|
|
|
CaseValsTy::const_iterator CI = CaseVals.begin();
|
|
|
|
CaseRangesTy::const_iterator RI = CaseRanges.begin();
|
|
|
|
EI = EnumVals.begin();
|
|
|
|
for (; EI != EIend; EI++) {
|
|
|
|
//Drop unneeded case values
|
|
|
|
llvm::APSInt CIVal;
|
|
|
|
while (CI != CaseVals.end() && CI->first < EI->first)
|
|
|
|
CI++;
|
|
|
|
|
|
|
|
if (CI != CaseVals.end() && CI->first == EI->first)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
//Drop unneeded case ranges
|
|
|
|
for (; RI != CaseRanges.end(); RI++) {
|
|
|
|
llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
|
|
|
|
if (EI->first <= Hi)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RI == CaseRanges.end() || EI->first < RI->first)
|
|
|
|
Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) << EI->second->getDeclName();
|
|
|
|
}
|
|
|
|
}
|
2007-08-23 14:23:56 +08:00
|
|
|
}
|
2009-05-16 07:57:33 +08:00
|
|
|
|
2009-05-16 15:39:55 +08: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 14:23:56 +08:00
|
|
|
if (CaseListIsErroneous)
|
2009-01-11 08:38:46 +08:00
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
Switch.release();
|
|
|
|
return Owned(SS);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2009-01-17 07:28:06 +08:00
|
|
|
Action::OwningStmtResult
|
2009-11-25 08:27:52 +08:00
|
|
|
Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
|
|
|
|
DeclPtrTy CondVar, StmtArg Body) {
|
|
|
|
OwningExprResult CondResult(Cond.release());
|
|
|
|
|
2009-11-25 05:15:44 +08:00
|
|
|
VarDecl *ConditionVar = 0;
|
2009-11-25 08:27:52 +08:00
|
|
|
if (CondVar.get()) {
|
|
|
|
ConditionVar = CondVar.getAs<VarDecl>();
|
|
|
|
CondResult = CheckConditionVariable(ConditionVar);
|
|
|
|
if (CondResult.isInvalid())
|
|
|
|
return StmtError();
|
2009-11-25 05:15:44 +08:00
|
|
|
}
|
2009-11-25 08:27:52 +08:00
|
|
|
Expr *ConditionExpr = CondResult.takeAs<Expr>();
|
|
|
|
if (!ConditionExpr)
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
if (CheckBooleanCondition(ConditionExpr, WhileLoc)) {
|
|
|
|
CondResult = ConditionExpr;
|
2009-10-13 05:59:07 +08:00
|
|
|
return StmtError();
|
2009-05-16 05:45:53 +08:00
|
|
|
}
|
2007-05-29 10:14:17 +08:00
|
|
|
|
2009-07-31 06:39:03 +08:00
|
|
|
Stmt *bodyStmt = Body.takeAs<Stmt>();
|
|
|
|
DiagnoseUnusedExprResult(bodyStmt);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-25 08:27:52 +08:00
|
|
|
CondResult.release();
|
|
|
|
return Owned(new (Context) WhileStmt(ConditionVar, ConditionExpr, bodyStmt,
|
2009-11-25 05:15:44 +08:00
|
|
|
WhileLoc));
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2009-01-17 07:28:06 +08:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
|
2009-06-13 07:04:47 +08:00
|
|
|
SourceLocation WhileLoc, SourceLocation CondLParen,
|
|
|
|
ExprArg Cond, SourceLocation CondRParen) {
|
2009-05-02 03:49:17 +08:00
|
|
|
Expr *condExpr = Cond.takeAs<Expr>();
|
2007-09-16 22:56:35 +08:00
|
|
|
assert(condExpr && "ActOnDoStmt(): missing expression");
|
2009-01-17 07:28:06 +08:00
|
|
|
|
2009-10-13 05:59:07 +08:00
|
|
|
if (CheckBooleanCondition(condExpr, DoLoc)) {
|
2009-05-16 05:56:04 +08:00
|
|
|
Cond = condExpr;
|
2009-10-13 05:59:07 +08:00
|
|
|
return StmtError();
|
2009-05-16 05:56:04 +08:00
|
|
|
}
|
2007-05-29 10:14:17 +08:00
|
|
|
|
2009-07-31 06:39:03 +08:00
|
|
|
Stmt *bodyStmt = Body.takeAs<Stmt>();
|
|
|
|
DiagnoseUnusedExprResult(bodyStmt);
|
|
|
|
|
2009-01-17 07:28:06 +08:00
|
|
|
Cond.release();
|
2009-07-31 06:39:03 +08:00
|
|
|
return Owned(new (Context) DoStmt(bodyStmt, condExpr, DoLoc,
|
2009-06-13 07:04:47 +08:00
|
|
|
WhileLoc, CondRParen));
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2009-01-17 07:28:06 +08:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
|
2009-11-25 08:27:52 +08:00
|
|
|
StmtArg first, FullExprArg second, DeclPtrTy secondVar,
|
|
|
|
FullExprArg third,
|
2009-01-17 07:28:06 +08:00
|
|
|
SourceLocation RParenLoc, StmtArg body) {
|
|
|
|
Stmt *First = static_cast<Stmt*>(first.get());
|
|
|
|
|
2008-09-10 10:17:11 +08:00
|
|
|
if (!getLangOptions().CPlusPlus) {
|
|
|
|
if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) {
|
2008-11-20 14:38:18 +08: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 10:17:11 +08: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 13:03:08 +08:00
|
|
|
}
|
2007-05-29 10:14:17 +08:00
|
|
|
}
|
2009-11-25 08:27:52 +08: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-13 05:59:07 +08:00
|
|
|
if (Second && CheckBooleanCondition(Second, ForLoc)) {
|
2009-11-25 08:27:52 +08:00
|
|
|
SecondResult = Second;
|
2009-10-13 05:59:07 +08:00
|
|
|
return StmtError();
|
2007-05-29 10:14:17 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-25 08:27:52 +08:00
|
|
|
Expr *Third = third.release().takeAs<Expr>();
|
|
|
|
Stmt *Body = static_cast<Stmt*>(body.get());
|
|
|
|
|
2009-08-01 09:39:59 +08:00
|
|
|
DiagnoseUnusedExprResult(First);
|
|
|
|
DiagnoseUnusedExprResult(Third);
|
2009-07-31 06:39:03 +08:00
|
|
|
DiagnoseUnusedExprResult(Body);
|
|
|
|
|
2009-01-17 07:28:06 +08:00
|
|
|
first.release();
|
|
|
|
body.release();
|
2009-11-25 08:27:52 +08:00
|
|
|
return Owned(new (Context) ForStmt(First, Second, ConditionVar, Third, Body,
|
|
|
|
ForLoc, LParenLoc, RParenLoc));
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2009-01-17 07:28:06 +08: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-11 04:33:58 +08:00
|
|
|
if (First) {
|
|
|
|
QualType FirstType;
|
|
|
|
if (DeclStmt *DS = dyn_cast<DeclStmt>(First)) {
|
2009-03-28 14:33:19 +08:00
|
|
|
if (!DS->isSingleDecl())
|
2009-01-17 07:28:06 +08:00
|
|
|
return StmtError(Diag((*DS->decl_begin())->getLocation(),
|
|
|
|
diag::err_toomany_element_decls));
|
|
|
|
|
2009-03-28 14:33:19 +08:00
|
|
|
Decl *D = DS->getSingleDecl();
|
2008-10-07 04:58:11 +08:00
|
|
|
FirstType = cast<ValueDecl>(D)->getType();
|
2008-11-20 14:38:18 +08: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-16 06:42:06 +08:00
|
|
|
VarDecl *VD = cast<VarDecl>(D);
|
|
|
|
if (VD->isBlockVarDecl() && !VD->hasLocalStorage())
|
2009-01-17 07:28:06 +08:00
|
|
|
return StmtError(Diag(VD->getLocation(),
|
|
|
|
diag::err_non_variable_decl_in_for));
|
2008-08-26 02:16:36 +08:00
|
|
|
} else {
|
2009-03-14 01:38:01 +08:00
|
|
|
if (cast<Expr>(First)->isLvalue(Context) != Expr::LV_Valid)
|
2009-01-17 07:28:06 +08:00
|
|
|
return StmtError(Diag(First->getLocStart(),
|
|
|
|
diag::err_selector_element_not_lvalue)
|
|
|
|
<< First->getSourceRange());
|
2008-08-26 02:16:36 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
FirstType = static_cast<Expr*>(First)->getType();
|
2008-08-26 02:16:36 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
if (!FirstType->isObjCObjectPointerType() &&
|
2009-08-15 05:53:27 +08:00
|
|
|
!FirstType->isBlockPointerType())
|
2008-11-19 13:27:50 +08:00
|
|
|
Diag(ForLoc, diag::err_selector_element_type)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< FirstType << First->getSourceRange();
|
2008-01-04 01:55:25 +08:00
|
|
|
}
|
|
|
|
if (Second) {
|
2010-02-03 08:27:59 +08:00
|
|
|
DefaultFunctionArrayLvalueConversion(Second);
|
2008-01-04 01:55:25 +08:00
|
|
|
QualType SecondType = Second->getType();
|
2009-07-16 23:41:00 +08:00
|
|
|
if (!SecondType->isObjCObjectPointerType())
|
2008-11-19 13:27:50 +08:00
|
|
|
Diag(ForLoc, diag::err_collection_expr_type)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< SecondType << Second->getSourceRange();
|
2008-01-04 01:55:25 +08:00
|
|
|
}
|
2009-01-17 07:28:06 +08:00
|
|
|
first.release();
|
|
|
|
second.release();
|
|
|
|
body.release();
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) ObjCForCollectionStmt(First, Second, Body,
|
|
|
|
ForLoc, RParenLoc));
|
2008-01-04 01:55:25 +08:00
|
|
|
}
|
2006-11-10 13:07:45 +08:00
|
|
|
|
2009-01-18 21:19:59 +08:00
|
|
|
Action::OwningStmtResult
|
2007-09-16 22:56:35 +08:00
|
|
|
Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
|
2006-11-10 13:07:45 +08:00
|
|
|
IdentifierInfo *LabelII) {
|
2007-05-28 14:28:18 +08:00
|
|
|
// Look up the record for this label identifier.
|
2009-04-19 04:01:55 +08:00
|
|
|
LabelStmt *&LabelDecl = getLabelMap()[LabelII];
|
2007-05-28 14:28:18 +08:00
|
|
|
|
2009-03-13 23:38:40 +08:00
|
|
|
// If we haven't seen this label yet, create a forward reference.
|
|
|
|
if (LabelDecl == 0)
|
2009-02-07 09:47:29 +08:00
|
|
|
LabelDecl = new (Context) LabelStmt(LabelLoc, LabelII, 0);
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) GotoStmt(LabelDecl, GotoLoc, LabelLoc));
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
2007-05-31 14:00:00 +08:00
|
|
|
|
2009-01-18 21:19:59 +08:00
|
|
|
Action::OwningStmtResult
|
2009-04-19 09:04:21 +08:00
|
|
|
Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
|
2009-01-18 21:19:59 +08:00
|
|
|
ExprArg DestExp) {
|
2009-03-26 08:18:06 +08:00
|
|
|
// Convert operand to void*
|
2009-03-26 15:32:37 +08:00
|
|
|
Expr* E = DestExp.takeAs<Expr>();
|
2009-05-16 08:20:29 +08:00
|
|
|
if (!E->isTypeDependent()) {
|
|
|
|
QualType ETy = E->getType();
|
2010-01-31 18:26:25 +08:00
|
|
|
QualType DestTy = Context.getPointerType(Context.VoidTy.withConst());
|
2009-05-16 08:20:29 +08:00
|
|
|
AssignConvertType ConvTy =
|
2010-01-31 18:26:25 +08:00
|
|
|
CheckSingleAssignmentConstraints(DestTy, E);
|
|
|
|
if (DiagnoseAssignmentResult(ConvTy, StarLoc, DestTy, ETy, E, AA_Passing))
|
2009-05-16 08:20:29 +08:00
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E));
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2009-01-18 21:19:59 +08:00
|
|
|
Action::OwningStmtResult
|
2007-09-16 22:56:35 +08:00
|
|
|
Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
|
2006-11-10 13:17:58 +08: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 21:19:59 +08:00
|
|
|
return StmtError(Diag(ContinueLoc, diag::err_continue_not_in_loop));
|
2006-11-10 13:17:58 +08:00
|
|
|
}
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) ContinueStmt(ContinueLoc));
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2009-01-18 21:19:59 +08:00
|
|
|
Action::OwningStmtResult
|
2007-09-16 22:56:35 +08:00
|
|
|
Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
|
2006-11-10 13:17:58 +08: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 21:19:59 +08:00
|
|
|
return StmtError(Diag(BreakLoc, diag::err_break_not_in_loop_or_switch));
|
2006-11-10 13:17:58 +08:00
|
|
|
}
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) BreakStmt(BreakLoc));
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2008-10-29 08:13:59 +08:00
|
|
|
/// ActOnBlockReturnStmt - Utility routine to figure out block's return type.
|
2008-09-04 02:15:37 +08:00
|
|
|
///
|
2009-01-18 21:19:59 +08:00
|
|
|
Action::OwningStmtResult
|
2008-09-04 02:15:37 +08: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.
|
Keep an explicit stack of function and block scopes, each element of
which has the label map, switch statement stack, etc. Previously, we
had a single set of maps in Sema (for the function) along with a stack
of block scopes. However, this lead to funky behavior with nested
functions, e.g., in the member functions of local classes.
The explicit-stack approach is far cleaner, and we retain a 1-element
cache so that we're not malloc/free'ing every time we enter a
function. Fixes PR6382.
Also, tweaked the unused-variable warning suppression logic to look at
errors within a given Scope rather than within a given function. The
prior code wasn't looking at the right number-of-errors count when
dealing with blocks, since the block's count would be deallocated
before we got to ActOnPopScope. This approach works with nested
blocks/functions, and gives tighter error recovery.
llvm-svn: 97518
2010-03-02 07:15:13 +08:00
|
|
|
BlockScopeInfo *CurBlock = getCurBlock();
|
2009-06-20 07:37:08 +08:00
|
|
|
if (CurBlock->ReturnType.isNull()) {
|
2008-09-17 06:25:10 +08:00
|
|
|
if (RetValExp) {
|
2008-09-25 06:26:48 +08:00
|
|
|
// Don't call UsualUnaryConversions(), since we don't want to do
|
|
|
|
// integer promotions here.
|
2010-02-03 08:27:59 +08:00
|
|
|
DefaultFunctionArrayLvalueConversion(RetValExp);
|
2009-06-20 07:37:08 +08: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-17 06:25:10 +08:00
|
|
|
} else
|
2009-06-20 07:37:08 +08:00
|
|
|
CurBlock->ReturnType = Context.VoidTy;
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
2009-06-20 07:37:08 +08:00
|
|
|
QualType FnRetType = CurBlock->ReturnType;
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
if (CurBlock->TheDecl->hasAttr<NoReturnAttr>()) {
|
2009-04-30 05:40:37 +08:00
|
|
|
Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr)
|
|
|
|
<< getCurFunctionOrMethodDecl()->getDeclName();
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
2008-09-04 02:15:37 +08: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 09:47:29 +08:00
|
|
|
RetValExp->Destroy(Context);
|
2008-09-04 02:15:37 +08:00
|
|
|
RetValExp = 0;
|
|
|
|
}
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
2009-01-18 21:19:59 +08:00
|
|
|
|
|
|
|
if (!RetValExp)
|
|
|
|
return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
|
|
|
|
|
2009-02-05 06:31:32 +08:00
|
|
|
if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
|
|
|
|
// we have a non-void block with an expression, continue checking
|
|
|
|
|
2009-09-09 23:08:12 +08: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-05 06:31:32 +08:00
|
|
|
// function return.
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2009-02-05 06:31:32 +08:00
|
|
|
// In C++ the return statement is handled via a copy initialization.
|
|
|
|
// the C version of which boils down to CheckSingleAssignmentConstraints.
|
2010-01-30 02:30:20 +08:00
|
|
|
OwningExprResult Res = PerformCopyInitialization(
|
|
|
|
InitializedEntity::InitializeResult(ReturnLoc,
|
|
|
|
FnRetType),
|
|
|
|
SourceLocation(),
|
|
|
|
Owned(RetValExp));
|
|
|
|
if (Res.isInvalid()) {
|
|
|
|
// FIXME: Cleanup temporaries here, anyway?
|
2009-02-05 06:31:32 +08:00
|
|
|
return StmtError();
|
2010-01-30 02:30:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
RetValExp = Res.takeAs<Expr>();
|
|
|
|
if (RetValExp)
|
|
|
|
CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
|
2009-02-05 06:31:32 +08:00
|
|
|
}
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
2006-11-10 13:07:45 +08:00
|
|
|
|
2009-04-13 01:16:29 +08: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-17 05:35:15 +08:00
|
|
|
if (!Ctx.hasSameUnqualifiedType(RetType, ExprType))
|
2009-04-13 01:16:29 +08: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 21:19:59 +08:00
|
|
|
Action::OwningStmtResult
|
2009-08-19 00:11:00 +08:00
|
|
|
Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
|
|
|
|
Expr *RetValExp = rex.takeAs<Expr>();
|
Keep an explicit stack of function and block scopes, each element of
which has the label map, switch statement stack, etc. Previously, we
had a single set of maps in Sema (for the function) along with a stack
of block scopes. However, this lead to funky behavior with nested
functions, e.g., in the member functions of local classes.
The explicit-stack approach is far cleaner, and we retain a 1-element
cache so that we're not malloc/free'ing every time we enter a
function. Fixes PR6382.
Also, tweaked the unused-variable warning suppression logic to look at
errors within a given Scope rather than within a given function. The
prior code wasn't looking at the right number-of-errors count when
dealing with blocks, since the block's count would be deallocated
before we got to ActOnPopScope. This approach works with nested
blocks/functions, and gives tighter error recovery.
llvm-svn: 97518
2010-03-02 07:15:13 +08:00
|
|
|
if (getCurBlock())
|
2008-09-04 02:15:37 +08:00
|
|
|
return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2008-12-05 07:50:19 +08:00
|
|
|
QualType FnRetType;
|
2009-04-29 08:43:21 +08:00
|
|
|
if (const FunctionDecl *FD = getCurFunctionDecl()) {
|
2008-12-05 07:50:19 +08:00
|
|
|
FnRetType = FD->getResultType();
|
2010-02-06 05:31:56 +08:00
|
|
|
if (FD->hasAttr<NoReturnAttr>() ||
|
|
|
|
FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
|
2009-06-01 03:32:13 +08:00
|
|
|
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
|
2009-04-29 08:43:21 +08:00
|
|
|
<< getCurFunctionOrMethodDecl()->getDeclName();
|
|
|
|
} else if (ObjCMethodDecl *MD = getCurMethodDecl())
|
2009-03-03 08:45:38 +08:00
|
|
|
FnRetType = MD->getResultType();
|
|
|
|
else // If we don't have a function/method context, bail.
|
|
|
|
return StmtError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-05 02:04:52 +08:00
|
|
|
if (FnRetType->isVoidType()) {
|
2009-10-02 07:25:31 +08:00
|
|
|
if (RetValExp && !RetValExp->isTypeDependent()) {
|
|
|
|
// C99 6.8.6.4p1 (ext_ since GCC warns)
|
2008-12-18 10:01:17 +08:00
|
|
|
unsigned D = diag::ext_return_has_expr;
|
|
|
|
if (RetValExp->getType()->isVoidType())
|
|
|
|
D = diag::ext_return_has_void_expr;
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2008-12-18 10:03:48 +08: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 23:08:12 +08:00
|
|
|
|
2009-12-16 04:51:39 +08:00
|
|
|
RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
|
2007-05-29 22:23:36 +08:00
|
|
|
}
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
|
2007-05-28 07:58:33 +08:00
|
|
|
}
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2009-05-15 08:48:27 +08:00
|
|
|
if (!RetValExp && !FnRetType->isDependentType()) {
|
2008-11-19 16:23:25 +08: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-24 05:45:46 +08:00
|
|
|
Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/;
|
2008-11-19 16:23:25 +08:00
|
|
|
else
|
2008-11-24 05:45:46 +08:00
|
|
|
Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) ReturnStmt(ReturnLoc, (Expr*)0));
|
2008-11-19 16:23:25 +08:00
|
|
|
}
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2008-12-06 07:32:09 +08:00
|
|
|
if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
|
|
|
|
// we have a non-void function with an expression, continue checking
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2009-09-09 23:08:12 +08: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 21:19:59 +08:00
|
|
|
// function return.
|
|
|
|
|
2009-04-13 01:16:29 +08: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;
|
Switch the initialization required by return statements over to the
new InitializationSequence. This fixes some bugs (e.g., PR5808),
changed some diagnostics, and caused more churn than expected. What's
new:
- InitializationSequence now has a "C conversion sequence" category
and step kind, which falls back to
- Changed the diagnostics for returns to always have the result type
of the function first and the type of the expression second.
CheckSingleAssignmentConstraints to peform checking in C.
- Improved ASTs for initialization of return values. The ASTs now
capture all of the temporaries we need to create, but
intentionally do not bind the tempoary that is actually returned,
so that it won't get destroyed twice.
- Make sure to perform an (elidable!) copy of the class object that
is returned from a class.
- Fix copy elision in CodeGen to properly see through the
subexpressions that occur with elidable copies.
- Give "new" its own entity kind; as with return values and thrown
objects, we don't bind the expression so we don't call a
destructor for it.
Note that, with this patch, I've broken returning move-only types in
C++0x. We'll fix it later, when we tackle NRVO.
llvm-svn: 91669
2009-12-18 13:02:21 +08:00
|
|
|
// FIXME: Elidable
|
|
|
|
(void)Elidable;
|
|
|
|
|
2008-12-06 07:32:09 +08:00
|
|
|
// In C++ the return statement is handled via a copy initialization.
|
2009-01-18 21:19:59 +08:00
|
|
|
// the C version of which boils down to CheckSingleAssignmentConstraints.
|
2009-12-19 01:31:58 +08:00
|
|
|
OwningExprResult Res = PerformCopyInitialization(
|
|
|
|
InitializedEntity::InitializeResult(ReturnLoc,
|
2009-12-22 23:35:07 +08:00
|
|
|
FnRetType),
|
2009-12-19 01:31:58 +08:00
|
|
|
SourceLocation(),
|
|
|
|
Owned(RetValExp));
|
|
|
|
if (Res.isInvalid()) {
|
Switch the initialization required by return statements over to the
new InitializationSequence. This fixes some bugs (e.g., PR5808),
changed some diagnostics, and caused more churn than expected. What's
new:
- InitializationSequence now has a "C conversion sequence" category
and step kind, which falls back to
- Changed the diagnostics for returns to always have the result type
of the function first and the type of the expression second.
CheckSingleAssignmentConstraints to peform checking in C.
- Improved ASTs for initialization of return values. The ASTs now
capture all of the temporaries we need to create, but
intentionally do not bind the tempoary that is actually returned,
so that it won't get destroyed twice.
- Make sure to perform an (elidable!) copy of the class object that
is returned from a class.
- Fix copy elision in CodeGen to properly see through the
subexpressions that occur with elidable copies.
- Give "new" its own entity kind; as with return values and thrown
objects, we don't bind the expression so we don't call a
destructor for it.
Note that, with this patch, I've broken returning move-only types in
C++0x. We'll fix it later, when we tackle NRVO.
llvm-svn: 91669
2009-12-18 13:02:21 +08:00
|
|
|
// FIXME: Cleanup temporaries here, anyway?
|
2009-01-18 21:19:59 +08:00
|
|
|
return StmtError();
|
2009-11-14 09:20:54 +08:00
|
|
|
}
|
Switch the initialization required by return statements over to the
new InitializationSequence. This fixes some bugs (e.g., PR5808),
changed some diagnostics, and caused more churn than expected. What's
new:
- InitializationSequence now has a "C conversion sequence" category
and step kind, which falls back to
- Changed the diagnostics for returns to always have the result type
of the function first and the type of the expression second.
CheckSingleAssignmentConstraints to peform checking in C.
- Improved ASTs for initialization of return values. The ASTs now
capture all of the temporaries we need to create, but
intentionally do not bind the tempoary that is actually returned,
so that it won't get destroyed twice.
- Make sure to perform an (elidable!) copy of the class object that
is returned from a class.
- Fix copy elision in CodeGen to properly see through the
subexpressions that occur with elidable copies.
- Give "new" its own entity kind; as with return values and thrown
objects, we don't bind the expression so we don't call a
destructor for it.
Note that, with this patch, I've broken returning move-only types in
C++0x. We'll fix it later, when we tackle NRVO.
llvm-svn: 91669
2009-12-18 13:02:21 +08:00
|
|
|
|
2009-12-19 01:31:58 +08:00
|
|
|
RetValExp = Res.takeAs<Expr>();
|
Switch the initialization required by return statements over to the
new InitializationSequence. This fixes some bugs (e.g., PR5808),
changed some diagnostics, and caused more churn than expected. What's
new:
- InitializationSequence now has a "C conversion sequence" category
and step kind, which falls back to
- Changed the diagnostics for returns to always have the result type
of the function first and the type of the expression second.
CheckSingleAssignmentConstraints to peform checking in C.
- Improved ASTs for initialization of return values. The ASTs now
capture all of the temporaries we need to create, but
intentionally do not bind the tempoary that is actually returned,
so that it won't get destroyed twice.
- Make sure to perform an (elidable!) copy of the class object that
is returned from a class.
- Fix copy elision in CodeGen to properly see through the
subexpressions that occur with elidable copies.
- Give "new" its own entity kind; as with return values and thrown
objects, we don't bind the expression so we don't call a
destructor for it.
Note that, with this patch, I've broken returning move-only types in
C++0x. We'll fix it later, when we tackle NRVO.
llvm-svn: 91669
2009-12-18 13:02:21 +08:00
|
|
|
if (RetValExp)
|
|
|
|
CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
|
2008-12-06 07:32:09 +08:00
|
|
|
}
|
|
|
|
|
2009-08-19 00:11:00 +08:00
|
|
|
if (RetValExp)
|
2009-12-16 04:51:39 +08:00
|
|
|
RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2009-03-14 01:38:01 +08: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) {
|
2010-01-24 13:50:09 +08:00
|
|
|
// Type dependent expressions will be checked during instantiation.
|
|
|
|
if (E->isTypeDependent())
|
|
|
|
return false;
|
|
|
|
|
2009-03-14 01:38:01 +08:00
|
|
|
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-19 00:53:17 +08:00
|
|
|
Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
|
|
|
|
bool IsSimple,
|
|
|
|
bool IsVolatile,
|
|
|
|
unsigned NumOutputs,
|
|
|
|
unsigned NumInputs,
|
2010-01-31 06:25:16 +08:00
|
|
|
IdentifierInfo **Names,
|
2009-01-19 00:53:17 +08:00
|
|
|
MultiExprArg constraints,
|
|
|
|
MultiExprArg exprs,
|
|
|
|
ExprArg asmString,
|
|
|
|
MultiExprArg clobbers,
|
2010-01-05 06:37:17 +08:00
|
|
|
SourceLocation RParenLoc,
|
|
|
|
bool MSAsm) {
|
2009-01-19 00:53:17 +08:00
|
|
|
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-28 04:38:24 +08:00
|
|
|
llvm::SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-19 03:55:17 +08:00
|
|
|
// The parser verifies that there is a string literal here.
|
2008-07-23 14:46:56 +08:00
|
|
|
if (AsmString->isWide())
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character)
|
|
|
|
<< AsmString->getSourceRange());
|
|
|
|
|
2008-08-19 03:55:17 +08:00
|
|
|
for (unsigned i = 0; i != NumOutputs; i++) {
|
|
|
|
StringLiteral *Literal = Constraints[i];
|
2008-07-23 14:46:56 +08:00
|
|
|
if (Literal->isWide())
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
|
|
|
|
<< Literal->getSourceRange());
|
|
|
|
|
2010-01-31 06:25:16 +08:00
|
|
|
llvm::StringRef OutputName;
|
|
|
|
if (Names[i])
|
|
|
|
OutputName = Names[i]->getName();
|
|
|
|
|
|
|
|
TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
|
2009-04-27 01:19:08 +08:00
|
|
|
if (!Context.Target.validateOutputConstraint(Info))
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),
|
2009-04-27 01:19:08 +08:00
|
|
|
diag::err_asm_invalid_output_constraint)
|
|
|
|
<< Info.getConstraintStr());
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2007-11-27 12:11:28 +08:00
|
|
|
// Check that the output exprs are valid lvalues.
|
2009-05-03 15:49:42 +08:00
|
|
|
Expr *OutputExpr = Exprs[i];
|
2009-03-14 01:38:01 +08:00
|
|
|
if (CheckAsmLValue(OutputExpr, *this)) {
|
2009-05-03 15:49:42 +08:00
|
|
|
return StmtError(Diag(OutputExpr->getLocStart(),
|
2008-11-19 13:27:50 +08:00
|
|
|
diag::err_asm_invalid_lvalue_in_output)
|
2009-05-03 15:49:42 +08:00
|
|
|
<< OutputExpr->getSourceRange());
|
2007-11-24 03:43:50 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-26 15:16:29 +08:00
|
|
|
OutputConstraintInfos.push_back(Info);
|
2007-11-24 03:43:50 +08:00
|
|
|
}
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2009-05-03 13:55:43 +08:00
|
|
|
llvm::SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
|
|
|
|
|
2007-11-24 03:43:50 +08:00
|
|
|
for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
|
2008-08-19 03:55:17 +08:00
|
|
|
StringLiteral *Literal = Constraints[i];
|
2008-07-23 14:46:56 +08:00
|
|
|
if (Literal->isWide())
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
|
|
|
|
<< Literal->getSourceRange());
|
|
|
|
|
2010-01-31 06:25:16 +08:00
|
|
|
llvm::StringRef InputName;
|
|
|
|
if (Names[i])
|
|
|
|
InputName = Names[i]->getName();
|
|
|
|
|
|
|
|
TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
|
2009-05-21 17:52:38 +08:00
|
|
|
if (!Context.Target.validateInputConstraint(OutputConstraintInfos.data(),
|
2009-04-27 01:57:12 +08:00
|
|
|
NumOutputs, Info)) {
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),
|
2009-04-27 01:19:08 +08:00
|
|
|
diag::err_asm_invalid_input_constraint)
|
|
|
|
<< Info.getConstraintStr());
|
2007-11-27 12:11:28 +08:00
|
|
|
}
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2009-05-03 15:49:42 +08:00
|
|
|
Expr *InputExpr = Exprs[i];
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2009-01-21 04:49:22 +08:00
|
|
|
// Only allow void types for memory constraints.
|
2009-04-26 15:16:29 +08:00
|
|
|
if (Info.allowsMemory() && !Info.allowsRegister()) {
|
2009-03-14 01:38:01 +08:00
|
|
|
if (CheckAsmLValue(InputExpr, *this))
|
2009-05-03 15:49:42 +08:00
|
|
|
return StmtError(Diag(InputExpr->getLocStart(),
|
2009-01-21 04:49:22 +08:00
|
|
|
diag::err_asm_invalid_lvalue_in_input)
|
2009-04-27 01:19:08 +08:00
|
|
|
<< Info.getConstraintStr()
|
2009-05-03 15:49:42 +08:00
|
|
|
<< InputExpr->getSourceRange());
|
2007-11-24 03:43:50 +08:00
|
|
|
}
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2009-04-26 15:16:29 +08:00
|
|
|
if (Info.allowsRegister()) {
|
2009-01-21 04:49:22 +08:00
|
|
|
if (InputExpr->getType()->isVoidType()) {
|
2009-05-03 15:49:42 +08:00
|
|
|
return StmtError(Diag(InputExpr->getLocStart(),
|
2009-01-21 04:49:22 +08:00
|
|
|
diag::err_asm_invalid_type_in_input)
|
2009-09-09 23:08:12 +08:00
|
|
|
<< InputExpr->getType() << Info.getConstraintStr()
|
2009-05-03 15:49:42 +08:00
|
|
|
<< InputExpr->getSourceRange());
|
2009-01-21 04:49:22 +08:00
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-03 08:27:59 +08:00
|
|
|
DefaultFunctionArrayLvalueConversion(Exprs[i]);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-03 13:55:43 +08:00
|
|
|
InputConstraintInfos.push_back(Info);
|
2007-11-24 03:43:50 +08:00
|
|
|
}
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2007-11-25 08:25:21 +08:00
|
|
|
// Check that the clobbers are valid.
|
2008-08-19 03:55:17 +08:00
|
|
|
for (unsigned i = 0; i != NumClobbers; i++) {
|
|
|
|
StringLiteral *Literal = Clobbers[i];
|
2008-07-23 14:46:56 +08:00
|
|
|
if (Literal->isWide())
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
|
|
|
|
<< Literal->getSourceRange());
|
|
|
|
|
2010-01-31 03:34:25 +08:00
|
|
|
llvm::StringRef Clobber = Literal->getString();
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2010-01-31 03:34:25 +08:00
|
|
|
if (!Context.Target.isValidGCCRegisterName(Clobber))
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),
|
2009-08-20 04:04:03 +08:00
|
|
|
diag::err_asm_unknown_register_name) << Clobber);
|
2007-11-25 08:25:21 +08:00
|
|
|
}
|
2009-01-19 00:53:17 +08:00
|
|
|
|
|
|
|
constraints.release();
|
|
|
|
exprs.release();
|
|
|
|
asmString.release();
|
|
|
|
clobbers.release();
|
2009-03-11 07:41:04 +08:00
|
|
|
AsmStmt *NS =
|
2010-01-31 07:19:41 +08:00
|
|
|
new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm,
|
|
|
|
NumOutputs, NumInputs, Names, Constraints, Exprs,
|
|
|
|
AsmString, NumClobbers, Clobbers, RParenLoc);
|
2009-03-11 07:41:04 +08:00
|
|
|
// 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-11 07:57:07 +08:00
|
|
|
Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
|
|
|
|
<< AsmString->getSourceRange();
|
2009-03-11 07:41:04 +08:00
|
|
|
DeleteStmt(NS);
|
|
|
|
return StmtError();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-03 13:55:43 +08: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 23:08:12 +08:00
|
|
|
|
2009-05-03 13:55:43 +08: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 23:08:12 +08:00
|
|
|
|
2009-05-03 13:55:43 +08:00
|
|
|
unsigned TiedTo = Info.getTiedOperand();
|
2009-05-03 15:04:21 +08:00
|
|
|
Expr *OutputExpr = Exprs[TiedTo];
|
2009-05-03 14:50:40 +08:00
|
|
|
Expr *InputExpr = Exprs[i+NumOutputs];
|
2009-05-03 13:59:17 +08:00
|
|
|
QualType InTy = InputExpr->getType();
|
|
|
|
QualType OutTy = OutputExpr->getType();
|
|
|
|
if (Context.hasSameType(InTy, OutTy))
|
2009-05-03 13:55:43 +08:00
|
|
|
continue; // All types can be tied to themselves.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-03 13:59:17 +08:00
|
|
|
// Int/ptr operands have some special cases that we allow.
|
|
|
|
if ((OutTy->isIntegerType() || OutTy->isPointerType()) &&
|
|
|
|
(InTy->isIntegerType() || InTy->isPointerType())) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-03 13:59:17 +08: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 16:32:32 +08:00
|
|
|
uint64_t OutSize = Context.getTypeSize(OutTy);
|
|
|
|
uint64_t InSize = Context.getTypeSize(InTy);
|
|
|
|
if (OutSize == InSize)
|
2009-05-03 13:55:43 +08:00
|
|
|
continue;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-03 16:32:32 +08: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 15:04:21 +08:00
|
|
|
// case now.
|
2009-05-03 16:32:32 +08:00
|
|
|
bool SmallerValueMentioned = false;
|
2009-05-03 16:24:16 +08:00
|
|
|
for (unsigned p = 0, e = Pieces.size(); p != e; ++p) {
|
|
|
|
AsmStmt::AsmStringPiece &Piece = Pieces[p];
|
|
|
|
if (!Piece.isOperand()) continue;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-03 16:32:32 +08: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 15:04:21 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-03 16:32:32 +08: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 15:04:21 +08:00
|
|
|
OutputConstraintInfos[TiedTo].allowsRegister())
|
|
|
|
continue;
|
2009-05-03 13:55:43 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-03 14:50:40 +08:00
|
|
|
Diag(InputExpr->getLocStart(),
|
2009-05-03 13:55:43 +08:00
|
|
|
diag::err_asm_tying_incompatible_types)
|
2009-05-03 13:59:17 +08:00
|
|
|
<< InTy << OutTy << OutputExpr->getSourceRange()
|
2009-05-03 13:55:43 +08:00
|
|
|
<< InputExpr->getSourceRange();
|
|
|
|
DeleteStmt(NS);
|
|
|
|
return StmtError();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-11 07:41:04 +08:00
|
|
|
return Owned(NS);
|
2007-10-29 12:04:16 +08:00
|
|
|
}
|
2007-11-02 07:59:59 +08:00
|
|
|
|
2009-01-19 01:43:11 +08:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
|
2009-03-29 03:18:32 +08:00
|
|
|
SourceLocation RParen, DeclPtrTy Parm,
|
2009-01-19 01:43:11 +08:00
|
|
|
StmtArg Body, StmtArg catchList) {
|
2009-05-02 03:30:39 +08:00
|
|
|
Stmt *CatchList = catchList.takeAs<Stmt>();
|
2009-03-29 03:18:32 +08:00
|
|
|
ParmVarDecl *PVD = cast_or_null<ParmVarDecl>(Parm.getAs<Decl>());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-04 04:59:06 +08:00
|
|
|
// PVD == 0 implies @catch(...).
|
2009-03-04 05:16:54 +08:00
|
|
|
if (PVD) {
|
2009-04-13 07:26:56 +08:00
|
|
|
// If we already know the decl is invalid, reject it.
|
|
|
|
if (PVD->isInvalidDecl())
|
|
|
|
return StmtError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-16 23:41:00 +08:00
|
|
|
if (!PVD->getType()->isObjCObjectPointerType())
|
2009-09-09 23:08:12 +08:00
|
|
|
return StmtError(Diag(PVD->getLocation(),
|
2009-03-04 05:16:54 +08:00
|
|
|
diag::err_catch_param_not_objc_type));
|
|
|
|
if (PVD->getType()->isObjCQualifiedIdType())
|
2009-09-09 23:08:12 +08:00
|
|
|
return StmtError(Diag(PVD->getLocation(),
|
2009-03-04 07:13:51 +08:00
|
|
|
diag::err_illegal_qualifiers_on_catch_parm));
|
2009-03-04 05:16:54 +08:00
|
|
|
}
|
2009-04-13 07:26:56 +08:00
|
|
|
|
2009-02-07 09:47:29 +08:00
|
|
|
ObjCAtCatchStmt *CS = new (Context) ObjCAtCatchStmt(AtLoc, RParen,
|
2009-05-02 03:49:17 +08:00
|
|
|
PVD, Body.takeAs<Stmt>(), CatchList);
|
2009-01-19 01:43:11 +08:00
|
|
|
return Owned(CatchList ? CatchList : CS);
|
2007-11-02 07:59:59 +08:00
|
|
|
}
|
|
|
|
|
2009-01-19 01:43:11 +08:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) {
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) ObjCAtFinallyStmt(AtLoc,
|
|
|
|
static_cast<Stmt*>(Body.release())));
|
2007-11-02 08:18:53 +08:00
|
|
|
}
|
2007-11-02 23:39:31 +08:00
|
|
|
|
2009-01-19 01:43:11 +08:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc,
|
|
|
|
StmtArg Try, StmtArg Catch, StmtArg Finally) {
|
Keep an explicit stack of function and block scopes, each element of
which has the label map, switch statement stack, etc. Previously, we
had a single set of maps in Sema (for the function) along with a stack
of block scopes. However, this lead to funky behavior with nested
functions, e.g., in the member functions of local classes.
The explicit-stack approach is far cleaner, and we retain a 1-element
cache so that we're not malloc/free'ing every time we enter a
function. Fixes PR6382.
Also, tweaked the unused-variable warning suppression logic to look at
errors within a given Scope rather than within a given function. The
prior code wasn't looking at the right number-of-errors count when
dealing with blocks, since the block's count would be deallocated
before we got to ActOnPopScope. This approach works with nested
blocks/functions, and gives tighter error recovery.
llvm-svn: 97518
2010-03-02 07:15:13 +08:00
|
|
|
FunctionNeedsScopeChecking() = true;
|
2009-05-02 03:49:17 +08:00
|
|
|
return Owned(new (Context) ObjCAtTryStmt(AtLoc, Try.takeAs<Stmt>(),
|
|
|
|
Catch.takeAs<Stmt>(),
|
|
|
|
Finally.takeAs<Stmt>()));
|
2007-11-02 23:39:31 +08:00
|
|
|
}
|
|
|
|
|
2010-04-23 05:44:01 +08:00
|
|
|
Sema::OwningStmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc,
|
|
|
|
ExprArg ThrowE) {
|
|
|
|
Expr *Throw = static_cast<Expr *>(ThrowE.get());
|
|
|
|
if (Throw) {
|
|
|
|
QualType ThrowType = Throw->getType();
|
|
|
|
// Make sure the expression type is an ObjC pointer or "void *".
|
|
|
|
if (!ThrowType->isDependentType() &&
|
|
|
|
!ThrowType->isObjCObjectPointerType()) {
|
|
|
|
const PointerType *PT = ThrowType->getAs<PointerType>();
|
|
|
|
if (!PT || !PT->getPointeeType()->isVoidType())
|
|
|
|
return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object)
|
|
|
|
<< Throw->getType() << Throw->getSourceRange());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowE.takeAs<Expr>()));
|
|
|
|
}
|
|
|
|
|
2009-01-19 01:43:11 +08:00
|
|
|
Action::OwningStmtResult
|
2010-04-23 05:44:01 +08:00
|
|
|
Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg Throw,
|
|
|
|
Scope *CurScope) {
|
|
|
|
if (!Throw.get()) {
|
2009-02-12 04:05:44 +08: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-13 02:09:32 +08:00
|
|
|
return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch));
|
2010-04-23 05:44:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return BuildObjCAtThrowStmt(AtLoc, move(Throw));
|
2007-11-07 10:00:49 +08:00
|
|
|
}
|
2007-11-02 23:39:31 +08:00
|
|
|
|
2009-01-19 01:43:11 +08:00
|
|
|
Action::OwningStmtResult
|
|
|
|
Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr,
|
|
|
|
StmtArg SynchBody) {
|
Keep an explicit stack of function and block scopes, each element of
which has the label map, switch statement stack, etc. Previously, we
had a single set of maps in Sema (for the function) along with a stack
of block scopes. However, this lead to funky behavior with nested
functions, e.g., in the member functions of local classes.
The explicit-stack approach is far cleaner, and we retain a 1-element
cache so that we're not malloc/free'ing every time we enter a
function. Fixes PR6382.
Also, tweaked the unused-variable warning suppression logic to look at
errors within a given Scope rather than within a given function. The
prior code wasn't looking at the right number-of-errors count when
dealing with blocks, since the block's count would be deallocated
before we got to ActOnPopScope. This approach works with nested
blocks/functions, and gives tighter error recovery.
llvm-svn: 97518
2010-03-02 07:15:13 +08:00
|
|
|
FunctionNeedsScopeChecking() = true;
|
2009-04-21 14:01:00 +08:00
|
|
|
|
2009-04-21 14:11:25 +08:00
|
|
|
// Make sure the expression type is an ObjC pointer or "void *".
|
|
|
|
Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get());
|
2009-07-16 23:41:00 +08:00
|
|
|
if (!SyncExpr->getType()->isObjCObjectPointerType()) {
|
2009-07-30 05:53:49 +08:00
|
|
|
const PointerType *PT = SyncExpr->getType()->getAs<PointerType>();
|
2009-04-21 14:11:25 +08:00
|
|
|
if (!PT || !PT->getPointeeType()->isVoidType())
|
|
|
|
return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object)
|
|
|
|
<< SyncExpr->getType() << SyncExpr->getSourceRange());
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc,
|
2009-05-02 03:49:17 +08:00
|
|
|
SynchExpr.takeAs<Stmt>(),
|
|
|
|
SynchBody.takeAs<Stmt>()));
|
2008-01-30 03:14:59 +08:00
|
|
|
}
|
2008-12-23 03:15:10 +08:00
|
|
|
|
|
|
|
/// ActOnCXXCatchBlock - Takes an exception declaration and a handler block
|
|
|
|
/// and creates a proper catch handler from them.
|
|
|
|
Action::OwningStmtResult
|
2009-03-29 03:18:32 +08:00
|
|
|
Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, DeclPtrTy ExDecl,
|
2008-12-23 03:15:10 +08:00
|
|
|
StmtArg HandlerBlock) {
|
|
|
|
// There's nothing to test that ActOnExceptionDecl didn't already test.
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) CXXCatchStmt(CatchLoc,
|
2009-03-29 03:18:32 +08:00
|
|
|
cast_or_null<VarDecl>(ExDecl.getAs<Decl>()),
|
2009-05-02 03:49:17 +08:00
|
|
|
HandlerBlock.takeAs<Stmt>()));
|
2008-12-23 03:15:10 +08:00
|
|
|
}
|
2008-12-23 05:35:02 +08:00
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
class TypeWithHandler {
|
|
|
|
QualType t;
|
|
|
|
CXXCatchStmt *stmt;
|
|
|
|
public:
|
|
|
|
TypeWithHandler(const QualType &type, CXXCatchStmt *statement)
|
|
|
|
: t(type), stmt(statement) {}
|
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
// An arbitrary order is fine as long as it places identical
|
|
|
|
// types next to each other.
|
2009-07-30 01:15:45 +08:00
|
|
|
bool operator<(const TypeWithHandler &y) const {
|
2009-09-25 03:53:00 +08:00
|
|
|
if (t.getAsOpaquePtr() < y.t.getAsOpaquePtr())
|
2009-07-30 01:15:45 +08:00
|
|
|
return true;
|
2009-09-25 03:53:00 +08:00
|
|
|
if (t.getAsOpaquePtr() > y.t.getAsOpaquePtr())
|
2009-07-30 01:15:45 +08:00
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return getTypeSpecStartLoc() < y.getTypeSpecStartLoc();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
bool operator==(const TypeWithHandler& other) const {
|
2009-09-25 03:53:00 +08:00
|
|
|
return t == other.t;
|
2009-07-30 01:15:45 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
QualType getQualType() const { return t; }
|
|
|
|
CXXCatchStmt *getCatchStmt() const { return stmt; }
|
|
|
|
SourceLocation getTypeSpecStartLoc() const {
|
|
|
|
return stmt->getExceptionDecl()->getTypeSpecStartLoc();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-12-23 05:35:02 +08: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-30 01:15:45 +08:00
|
|
|
llvm::SmallVector<TypeWithHandler, 8> TypesWithHandlers;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
for (unsigned i = 0; i < NumHandlers; ++i) {
|
2008-12-23 05:35:02 +08:00
|
|
|
CXXCatchStmt *Handler = llvm::cast<CXXCatchStmt>(Handlers[i]);
|
2009-07-30 01:15:45 +08:00
|
|
|
if (!Handler->getExceptionDecl()) {
|
|
|
|
if (i < NumHandlers - 1)
|
|
|
|
return StmtError(Diag(Handler->getLocStart(),
|
|
|
|
diag::err_early_catch_all));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08: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 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
TypeWithHandler prev = TypesWithHandlers[0];
|
|
|
|
for (unsigned i = 1; i < TypesWithHandlers.size(); ++i) {
|
|
|
|
TypeWithHandler curr = TypesWithHandlers[i];
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08: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 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
prev = curr;
|
|
|
|
}
|
2008-12-23 05:35:02 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-23 05:35:02 +08: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.
|
|
|
|
|
Keep an explicit stack of function and block scopes, each element of
which has the label map, switch statement stack, etc. Previously, we
had a single set of maps in Sema (for the function) along with a stack
of block scopes. However, this lead to funky behavior with nested
functions, e.g., in the member functions of local classes.
The explicit-stack approach is far cleaner, and we retain a 1-element
cache so that we're not malloc/free'ing every time we enter a
function. Fixes PR6382.
Also, tweaked the unused-variable warning suppression logic to look at
errors within a given Scope rather than within a given function. The
prior code wasn't looking at the right number-of-errors count when
dealing with blocks, since the block's count would be deallocated
before we got to ActOnPopScope. This approach works with nested
blocks/functions, and gives tighter error recovery.
llvm-svn: 97518
2010-03-02 07:15:13 +08:00
|
|
|
FunctionNeedsScopeChecking() = true;
|
2008-12-23 05:35:02 +08:00
|
|
|
RawHandlers.release();
|
2010-02-03 11:56:39 +08:00
|
|
|
return Owned(CXXTryStmt::Create(Context, TryLoc,
|
|
|
|
static_cast<Stmt*>(TryBlock.release()),
|
|
|
|
Handlers, NumHandlers));
|
2008-12-23 05:35:02 +08:00
|
|
|
}
|