diff options
Diffstat (limited to 'lib/Sema/SemaStmt.cpp')
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 246 |
1 files changed, 189 insertions, 57 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index d0f214f..de67a5f 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -15,9 +15,11 @@ #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" @@ -59,6 +61,15 @@ Sema::OwningStmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, return Owned(new (Context) DeclStmt(DG, StartLoc, EndLoc)); } +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(); +} + void Sema::DiagnoseUnusedExprResult(const Stmt *S) { const Expr *E = dyn_cast_or_null<Expr>(S); if (!E) @@ -225,16 +236,24 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, } Action::OwningStmtResult -Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, +Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar, StmtArg ThenVal, SourceLocation ElseLoc, StmtArg ElseVal) { OwningExprResult CondResult(CondVal.release()); - Expr *condExpr = CondResult.takeAs<Expr>(); - - assert(condExpr && "ActOnIfStmt(): missing expression"); - if (CheckBooleanCondition(condExpr, IfLoc)) { - CondResult = condExpr; + VarDecl *ConditionVar = 0; + if (CondVar.get()) { + ConditionVar = CondVar.getAs<VarDecl>(); + CondResult = CheckConditionVariable(ConditionVar); + if (CondResult.isInvalid()) + return StmtError(); + } + Expr *ConditionExpr = CondResult.takeAs<Expr>(); + if (!ConditionExpr) + return StmtError(); + + if (CheckBooleanCondition(ConditionExpr, IfLoc)) { + CondResult = ConditionExpr; return StmtError(); } @@ -254,41 +273,23 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DiagnoseUnusedExprResult(elseStmt); CondResult.release(); - return Owned(new (Context) IfStmt(IfLoc, condExpr, thenStmt, - ElseLoc, elseStmt)); + return Owned(new (Context) IfStmt(IfLoc, ConditionVar, ConditionExpr, + thenStmt, ElseLoc, elseStmt)); } Action::OwningStmtResult -Sema::ActOnStartOfSwitchStmt(ExprArg cond) { - Expr *Cond = cond.takeAs<Expr>(); - - if (getLangOptions().CPlusPlus) { - // 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. - if (!Cond->isTypeDependent()) { - QualType Ty = Cond->getType(); - - // FIXME: Handle class types. - - // If the type is wrong a diagnostic will be emitted later at - // ActOnFinishSwitchStmt. - if (Ty->isIntegralType() || Ty->isEnumeralType()) { - // Integral promotions are performed. - // FIXME: Integral promotions for C++ are not complete. - UsualUnaryConversions(Cond); - } - } - } else { - // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. - UsualUnaryConversions(Cond); +Sema::ActOnStartOfSwitchStmt(FullExprArg cond, DeclPtrTy CondVar) { + OwningExprResult CondResult(cond.release()); + + VarDecl *ConditionVar = 0; + if (CondVar.get()) { + ConditionVar = CondVar.getAs<VarDecl>(); + CondResult = CheckConditionVariable(ConditionVar); + if (CondResult.isInvalid()) + return StmtError(); } - - SwitchStmt *SS = new (Context) SwitchStmt(Cond); + SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar, + CondResult.takeAs<Expr>()); getSwitchStack().push_back(SS); return Owned(SS); } @@ -383,6 +384,103 @@ static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) { return expr->getType(); } +/// \brief Check (and possibly convert) the condition in a switch +/// statement in C++. +static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, + Expr *&CondExpr) { + if (CondExpr->isTypeDependent()) + return false; + + QualType CondType = CondExpr->getType(); + + // C++ 6.4.2.p2: + // The condition shall be of integral type, enumeration type, or of a class + // type for which a single conversion function to integral or enumeration + // type exists (12.3). If the condition is of class type, the condition is + // converted by calling that conversion function, and the result of the + // conversion is used in place of the original condition for the remainder + // of this section. Integral promotions are performed. + + // Make sure that the condition expression has a complete type, + // otherwise we'll never find any conversions. + if (S.RequireCompleteType(SwitchLoc, CondType, + PDiag(diag::err_switch_incomplete_class_type) + << CondExpr->getSourceRange())) + return true; + + llvm::SmallVector<CXXConversionDecl *, 4> ViableConversions; + llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions; + if (const RecordType *RecordTy = CondType->getAs<RecordType>()) { + const UnresolvedSet *Conversions + = cast<CXXRecordDecl>(RecordTy->getDecl()) + ->getVisibleConversionFunctions(); + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { + if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*I)) + if (Conversion->getConversionType().getNonReferenceType() + ->isIntegralType()) { + if (Conversion->isExplicit()) + ExplicitConversions.push_back(Conversion); + else + ViableConversions.push_back(Conversion); + } + } + + switch (ViableConversions.size()) { + case 0: + if (ExplicitConversions.size() == 1) { + // The user probably meant to invoke the given explicit + // conversion; use it. + QualType ConvTy + = ExplicitConversions[0]->getConversionType() + .getNonReferenceType(); + std::string TypeStr; + ConvTy.getAsStringInternal(TypeStr, S.Context.PrintingPolicy); + + S.Diag(SwitchLoc, diag::err_switch_explicit_conversion) + << CondType << ConvTy << CondExpr->getSourceRange() + << CodeModificationHint::CreateInsertion(CondExpr->getLocStart(), + "static_cast<" + TypeStr + ">(") + << CodeModificationHint::CreateInsertion( + S.PP.getLocForEndOfToken(CondExpr->getLocEnd()), + ")"); + S.Diag(ExplicitConversions[0]->getLocation(), + diag::note_switch_conversion) + << ConvTy->isEnumeralType() << ConvTy; + + // If we aren't in a SFINAE context, build a call to the + // explicit conversion function. + if (S.isSFINAEContext()) + return true; + + CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ExplicitConversions[0]); + } + + // We'll complain below about a non-integral condition type. + break; + + case 1: + // Apply this conversion. + CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ViableConversions[0]); + break; + + default: + S.Diag(SwitchLoc, diag::err_switch_multiple_conversions) + << CondType << CondExpr->getSourceRange(); + for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) { + QualType ConvTy + = ViableConversions[I]->getConversionType().getNonReferenceType(); + S.Diag(ViableConversions[I]->getLocation(), + diag::note_switch_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + return true; + } + } + + return false; +} + Action::OwningStmtResult Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body) { @@ -394,8 +492,23 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, SS->setBody(BodyStmt, SwitchLoc); getSwitchStack().pop_back(); + if (SS->getCond() == 0) { + SS->Destroy(Context); + return StmtError(); + } + Expr *CondExpr = SS->getCond(); + QualType CondTypeBeforePromotion = + GetTypeBeforeIntegralPromotion(CondExpr); + + if (getLangOptions().CPlusPlus && + CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr)) + return StmtError(); + + // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. + UsualUnaryConversions(CondExpr); QualType CondType = CondExpr->getType(); + SS->setCond(CondExpr); // C++ 6.4.2.p2: // Integral promotions are performed (on the switch condition). @@ -404,9 +517,6 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // 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. - QualType CondTypeBeforePromotion = - GetTypeBeforeIntegralPromotion(CondExpr); - if (!CondExpr->isTypeDependent()) { if (!CondType->isIntegerType()) { // C99 6.8.4.2p1 Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer) @@ -614,21 +724,32 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, } Action::OwningStmtResult -Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, StmtArg Body) { - ExprArg CondArg(Cond.release()); - Expr *condExpr = CondArg.takeAs<Expr>(); - assert(condExpr && "ActOnWhileStmt(): missing expression"); - - if (CheckBooleanCondition(condExpr, WhileLoc)) { - CondArg = condExpr; +Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, + DeclPtrTy CondVar, StmtArg Body) { + OwningExprResult CondResult(Cond.release()); + + VarDecl *ConditionVar = 0; + if (CondVar.get()) { + ConditionVar = CondVar.getAs<VarDecl>(); + CondResult = CheckConditionVariable(ConditionVar); + if (CondResult.isInvalid()) + return StmtError(); + } + Expr *ConditionExpr = CondResult.takeAs<Expr>(); + if (!ConditionExpr) + return StmtError(); + + if (CheckBooleanCondition(ConditionExpr, WhileLoc)) { + CondResult = ConditionExpr; return StmtError(); } Stmt *bodyStmt = Body.takeAs<Stmt>(); DiagnoseUnusedExprResult(bodyStmt); - CondArg.release(); - return Owned(new (Context) WhileStmt(condExpr, bodyStmt, WhileLoc)); + CondResult.release(); + return Owned(new (Context) WhileStmt(ConditionVar, ConditionExpr, bodyStmt, + WhileLoc)); } Action::OwningStmtResult @@ -653,12 +774,10 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, Action::OwningStmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - StmtArg first, ExprArg second, ExprArg third, + StmtArg first, FullExprArg second, DeclPtrTy secondVar, + FullExprArg third, SourceLocation RParenLoc, StmtArg body) { Stmt *First = static_cast<Stmt*>(first.get()); - Expr *Second = second.takeAs<Expr>(); - Expr *Third = static_cast<Expr*>(third.get()); - Stmt *Body = static_cast<Stmt*>(body.get()); if (!getLangOptions().CPlusPlus) { if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) { @@ -676,20 +795,33 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, } } } + + 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>(); if (Second && CheckBooleanCondition(Second, ForLoc)) { - second = Second; + SecondResult = Second; return StmtError(); } + Expr *Third = third.release().takeAs<Expr>(); + Stmt *Body = static_cast<Stmt*>(body.get()); + DiagnoseUnusedExprResult(First); DiagnoseUnusedExprResult(Third); DiagnoseUnusedExprResult(Body); first.release(); - third.release(); body.release(); - return Owned(new (Context) ForStmt(First, Second, Third, Body, ForLoc, - LParenLoc, RParenLoc)); + return Owned(new (Context) ForStmt(First, Second, ConditionVar, Third, Body, + ForLoc, LParenLoc, RParenLoc)); } Action::OwningStmtResult |