diff options
Diffstat (limited to 'lib/Sema/SemaStmt.cpp')
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 573 |
1 files changed, 376 insertions, 197 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 248665a..9bd8678 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -65,7 +65,7 @@ StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc, StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc, SourceLocation EndLoc) { - DeclGroupRef DG = dg.getAsVal<DeclGroupRef>(); + DeclGroupRef DG = dg.get(); // If we have an invalid decl, just return an error. if (DG.isNull()) return StmtError(); @@ -74,7 +74,7 @@ StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc, } void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) { - DeclGroupRef DG = dg.getAsVal<DeclGroupRef>(); + DeclGroupRef DG = dg.get(); // If we don't have a declaration, or we have an invalid declaration, // just return. @@ -93,9 +93,6 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) { return; } - // suppress any potential 'unused variable' warning. - var->setUsed(); - // foreach variables are never actually initialized in the way that // the parser came up with. var->setInit(0); @@ -294,11 +291,10 @@ sema::CompoundScopeInfo &Sema::getCurCompoundScope() const { return getCurFunction()->CompoundScopes.back(); } -StmtResult -Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, - MultiStmtArg elts, bool isStmtExpr) { - unsigned NumElts = elts.size(); - Stmt **Elts = elts.data(); +StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, + ArrayRef<Stmt *> Elts, bool isStmtExpr) { + const unsigned NumElts = Elts.size(); + // If we're in C89 mode, check that we don't have any decls after stmts. If // so, emit an extension diagnostic. if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) { @@ -335,9 +331,7 @@ Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, DiagnoseEmptyLoopBody(Elts[i], Elts[i + 1]); } - return Owned(new (Context) CompoundStmt(Context, - llvm::makeArrayRef(Elts, NumElts), - L, R)); + return Owned(new (Context) CompoundStmt(Context, Elts, L, R)); } StmtResult @@ -592,52 +586,50 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, public: SwitchConvertDiagnoser(Expr *Cond) - : ICEConvertDiagnoser(false, true), Cond(Cond) { } + : ICEConvertDiagnoser(/*AllowScopedEnumerations*/true, false, true), + Cond(Cond) {} - virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, - QualType T) { + virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, + QualType T) { return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T; } - virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, - QualType T) { + virtual SemaDiagnosticBuilder diagnoseIncomplete( + Sema &S, SourceLocation Loc, QualType T) { return S.Diag(Loc, diag::err_switch_incomplete_class_type) << T << Cond->getSourceRange(); } - virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc, - QualType T, - QualType ConvTy) { + virtual SemaDiagnosticBuilder diagnoseExplicitConv( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) { return S.Diag(Loc, diag::err_switch_explicit_conversion) << T << ConvTy; } - virtual DiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, - QualType ConvTy) { + virtual SemaDiagnosticBuilder noteExplicitConv( + Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { return S.Diag(Conv->getLocation(), diag::note_switch_conversion) << ConvTy->isEnumeralType() << ConvTy; } - virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, - QualType T) { + virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, + QualType T) { return S.Diag(Loc, diag::err_switch_multiple_conversions) << T; } - virtual DiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, - QualType ConvTy) { + virtual SemaDiagnosticBuilder noteAmbiguous( + Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { return S.Diag(Conv->getLocation(), diag::note_switch_conversion) << ConvTy->isEnumeralType() << ConvTy; } - virtual DiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, - QualType T, - QualType ConvTy) { - return DiagnosticBuilder::getEmpty(); + virtual SemaDiagnosticBuilder diagnoseConversion( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) { + llvm_unreachable("conversion functions are permitted"); } } SwitchDiagnoser(Cond); - CondResult - = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond, SwitchDiagnoser, - /*AllowScopedEnumerations*/ true); + CondResult = + PerformContextualImplicitConversion(SwitchLoc, Cond, SwitchDiagnoser); if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.take(); @@ -1122,9 +1114,9 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, void Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, Expr *SrcExpr) { - unsigned DIAG = diag::warn_not_in_enum_assignement; - if (Diags.getDiagnosticLevel(DIAG, SrcExpr->getExprLoc()) - == DiagnosticsEngine::Ignored) + if (Diags.getDiagnosticLevel(diag::warn_not_in_enum_assignment, + SrcExpr->getExprLoc()) == + DiagnosticsEngine::Ignored) return; if (const EnumType *ET = DstType->getAs<EnumType>()) @@ -1133,13 +1125,14 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, if (!SrcExpr->isTypeDependent() && !SrcExpr->isValueDependent() && SrcExpr->isIntegerConstantExpr(Context)) { // Get the bitwidth of the enum value before promotions. - unsigned DstWith = Context.getIntWidth(DstType); + unsigned DstWidth = Context.getIntWidth(DstType); bool DstIsSigned = DstType->isSignedIntegerOrEnumerationType(); llvm::APSInt RhsVal = SrcExpr->EvaluateKnownConstInt(Context); + AdjustAPSInt(RhsVal, DstWidth, DstIsSigned); const EnumDecl *ED = ET->getDecl(); - typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> - EnumValsTy; + typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl *>, 64> + EnumValsTy; EnumValsTy EnumVals; // Gather all enum values, set their type and sort them, @@ -1147,21 +1140,21 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(); EDI != ED->enumerator_end(); ++EDI) { llvm::APSInt Val = EDI->getInitVal(); - AdjustAPSInt(Val, DstWith, DstIsSigned); + AdjustAPSInt(Val, DstWidth, DstIsSigned); EnumVals.push_back(std::make_pair(Val, *EDI)); } if (EnumVals.empty()) return; std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals); EnumValsTy::iterator EIend = - std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); + std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); - // See which case values aren't in enum. + // See which values aren't in the enum. EnumValsTy::const_iterator EI = EnumVals.begin(); while (EI != EIend && EI->first < RhsVal) EI++; if (EI == EIend || EI->first != RhsVal) { - Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignement) + Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment) << DstType; } } @@ -1220,77 +1213,77 @@ namespace { // of the excluded constructs are used. class DeclExtractor : public EvaluatedExprVisitor<DeclExtractor> { llvm::SmallPtrSet<VarDecl*, 8> &Decls; - SmallVector<SourceRange, 10> &Ranges; + SmallVectorImpl<SourceRange> &Ranges; bool Simple; -public: - typedef EvaluatedExprVisitor<DeclExtractor> Inherited; - - DeclExtractor(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls, - SmallVector<SourceRange, 10> &Ranges) : - Inherited(S.Context), - Decls(Decls), - Ranges(Ranges), - Simple(true) {} + public: + typedef EvaluatedExprVisitor<DeclExtractor> Inherited; - bool isSimple() { return Simple; } + DeclExtractor(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls, + SmallVectorImpl<SourceRange> &Ranges) : + Inherited(S.Context), + Decls(Decls), + Ranges(Ranges), + Simple(true) {} - // Replaces the method in EvaluatedExprVisitor. - void VisitMemberExpr(MemberExpr* E) { - Simple = false; - } + bool isSimple() { return Simple; } - // Any Stmt not whitelisted will cause the condition to be marked complex. - void VisitStmt(Stmt *S) { - Simple = false; - } + // Replaces the method in EvaluatedExprVisitor. + void VisitMemberExpr(MemberExpr* E) { + Simple = false; + } - void VisitBinaryOperator(BinaryOperator *E) { - Visit(E->getLHS()); - Visit(E->getRHS()); - } + // Any Stmt not whitelisted will cause the condition to be marked complex. + void VisitStmt(Stmt *S) { + Simple = false; + } - void VisitCastExpr(CastExpr *E) { - Visit(E->getSubExpr()); - } + void VisitBinaryOperator(BinaryOperator *E) { + Visit(E->getLHS()); + Visit(E->getRHS()); + } - void VisitUnaryOperator(UnaryOperator *E) { - // Skip checking conditionals with derefernces. - if (E->getOpcode() == UO_Deref) - Simple = false; - else + void VisitCastExpr(CastExpr *E) { Visit(E->getSubExpr()); - } + } - void VisitConditionalOperator(ConditionalOperator *E) { - Visit(E->getCond()); - Visit(E->getTrueExpr()); - Visit(E->getFalseExpr()); - } + void VisitUnaryOperator(UnaryOperator *E) { + // Skip checking conditionals with derefernces. + if (E->getOpcode() == UO_Deref) + Simple = false; + else + Visit(E->getSubExpr()); + } - void VisitParenExpr(ParenExpr *E) { - Visit(E->getSubExpr()); - } + void VisitConditionalOperator(ConditionalOperator *E) { + Visit(E->getCond()); + Visit(E->getTrueExpr()); + Visit(E->getFalseExpr()); + } - void VisitBinaryConditionalOperator(BinaryConditionalOperator *E) { - Visit(E->getOpaqueValue()->getSourceExpr()); - Visit(E->getFalseExpr()); - } + void VisitParenExpr(ParenExpr *E) { + Visit(E->getSubExpr()); + } + + void VisitBinaryConditionalOperator(BinaryConditionalOperator *E) { + Visit(E->getOpaqueValue()->getSourceExpr()); + Visit(E->getFalseExpr()); + } - void VisitIntegerLiteral(IntegerLiteral *E) { } - void VisitFloatingLiteral(FloatingLiteral *E) { } - void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { } - void VisitCharacterLiteral(CharacterLiteral *E) { } - void VisitGNUNullExpr(GNUNullExpr *E) { } - void VisitImaginaryLiteral(ImaginaryLiteral *E) { } + void VisitIntegerLiteral(IntegerLiteral *E) { } + void VisitFloatingLiteral(FloatingLiteral *E) { } + void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { } + void VisitCharacterLiteral(CharacterLiteral *E) { } + void VisitGNUNullExpr(GNUNullExpr *E) { } + void VisitImaginaryLiteral(ImaginaryLiteral *E) { } - void VisitDeclRefExpr(DeclRefExpr *E) { - VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()); - if (!VD) return; + void VisitDeclRefExpr(DeclRefExpr *E) { + VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()); + if (!VD) return; - Ranges.push_back(E->getSourceRange()); + Ranges.push_back(E->getSourceRange()); - Decls.insert(VD); - } + Decls.insert(VD); + } }; // end class DeclExtractor @@ -1300,66 +1293,67 @@ public: llvm::SmallPtrSet<VarDecl*, 8> &Decls; bool FoundDecl; -public: - typedef EvaluatedExprVisitor<DeclMatcher> Inherited; + public: + typedef EvaluatedExprVisitor<DeclMatcher> Inherited; - DeclMatcher(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls, Stmt *Statement) : - Inherited(S.Context), Decls(Decls), FoundDecl(false) { - if (!Statement) return; + DeclMatcher(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls, + Stmt *Statement) : + Inherited(S.Context), Decls(Decls), FoundDecl(false) { + if (!Statement) return; - Visit(Statement); - } + Visit(Statement); + } - void VisitReturnStmt(ReturnStmt *S) { - FoundDecl = true; - } + void VisitReturnStmt(ReturnStmt *S) { + FoundDecl = true; + } - void VisitBreakStmt(BreakStmt *S) { - FoundDecl = true; - } + void VisitBreakStmt(BreakStmt *S) { + FoundDecl = true; + } - void VisitGotoStmt(GotoStmt *S) { - FoundDecl = true; - } + void VisitGotoStmt(GotoStmt *S) { + FoundDecl = true; + } - void VisitCastExpr(CastExpr *E) { - if (E->getCastKind() == CK_LValueToRValue) - CheckLValueToRValueCast(E->getSubExpr()); - else - Visit(E->getSubExpr()); - } + void VisitCastExpr(CastExpr *E) { + if (E->getCastKind() == CK_LValueToRValue) + CheckLValueToRValueCast(E->getSubExpr()); + else + Visit(E->getSubExpr()); + } - void CheckLValueToRValueCast(Expr *E) { - E = E->IgnoreParenImpCasts(); + void CheckLValueToRValueCast(Expr *E) { + E = E->IgnoreParenImpCasts(); - if (isa<DeclRefExpr>(E)) { - return; - } + if (isa<DeclRefExpr>(E)) { + return; + } - if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { - Visit(CO->getCond()); - CheckLValueToRValueCast(CO->getTrueExpr()); - CheckLValueToRValueCast(CO->getFalseExpr()); - return; - } + if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { + Visit(CO->getCond()); + CheckLValueToRValueCast(CO->getTrueExpr()); + CheckLValueToRValueCast(CO->getFalseExpr()); + return; + } - if (BinaryConditionalOperator *BCO = - dyn_cast<BinaryConditionalOperator>(E)) { - CheckLValueToRValueCast(BCO->getOpaqueValue()->getSourceExpr()); - CheckLValueToRValueCast(BCO->getFalseExpr()); - return; - } + if (BinaryConditionalOperator *BCO = + dyn_cast<BinaryConditionalOperator>(E)) { + CheckLValueToRValueCast(BCO->getOpaqueValue()->getSourceExpr()); + CheckLValueToRValueCast(BCO->getFalseExpr()); + return; + } - Visit(E); - } + Visit(E); + } - void VisitDeclRefExpr(DeclRefExpr *E) { - if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) - if (Decls.count(VD)) - FoundDecl = true; - } + void VisitDeclRefExpr(DeclRefExpr *E) { + if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) + if (Decls.count(VD)) + FoundDecl = true; + } - bool FoundDeclInUse() { return FoundDecl; } + bool FoundDeclInUse() { return FoundDecl; } }; // end class DeclMatcher @@ -1411,7 +1405,7 @@ public: // Load SourceRanges into diagnostic if there is room. // Otherwise, load the SourceRange of the conditional expression. if (Ranges.size() <= PartialDiagnostic::MaxArguments) - for (SmallVector<SourceRange, 10>::iterator I = Ranges.begin(), + for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) PDiag << *I; @@ -1421,6 +1415,104 @@ public: S.Diag(Ranges.begin()->getBegin(), PDiag); } + // If Statement is an incemement or decrement, return true and sets the + // variables Increment and DRE. + bool ProcessIterationStmt(Sema &S, Stmt* Statement, bool &Increment, + DeclRefExpr *&DRE) { + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(Statement)) { + switch (UO->getOpcode()) { + default: return false; + case UO_PostInc: + case UO_PreInc: + Increment = true; + break; + case UO_PostDec: + case UO_PreDec: + Increment = false; + break; + } + DRE = dyn_cast<DeclRefExpr>(UO->getSubExpr()); + return DRE; + } + + if (CXXOperatorCallExpr *Call = dyn_cast<CXXOperatorCallExpr>(Statement)) { + FunctionDecl *FD = Call->getDirectCallee(); + if (!FD || !FD->isOverloadedOperator()) return false; + switch (FD->getOverloadedOperator()) { + default: return false; + case OO_PlusPlus: + Increment = true; + break; + case OO_MinusMinus: + Increment = false; + break; + } + DRE = dyn_cast<DeclRefExpr>(Call->getArg(0)); + return DRE; + } + + return false; + } + + // A visitor to determine if a continue statement is a subexpression. + class ContinueFinder : public EvaluatedExprVisitor<ContinueFinder> { + bool Found; + public: + ContinueFinder(Sema &S, Stmt* Body) : + Inherited(S.Context), + Found(false) { + Visit(Body); + } + + typedef EvaluatedExprVisitor<ContinueFinder> Inherited; + + void VisitContinueStmt(ContinueStmt* E) { + Found = true; + } + + bool ContinueFound() { return Found; } + + }; // end class ContinueFinder + + // Emit a warning when a loop increment/decrement appears twice per loop + // iteration. The conditions which trigger this warning are: + // 1) The last statement in the loop body and the third expression in the + // for loop are both increment or both decrement of the same variable + // 2) No continue statements in the loop body. + void CheckForRedundantIteration(Sema &S, Expr *Third, Stmt *Body) { + // Return when there is nothing to check. + if (!Body || !Third) return; + + if (S.Diags.getDiagnosticLevel(diag::warn_redundant_loop_iteration, + Third->getLocStart()) + == DiagnosticsEngine::Ignored) + return; + + // Get the last statement from the loop body. + CompoundStmt *CS = dyn_cast<CompoundStmt>(Body); + if (!CS || CS->body_empty()) return; + Stmt *LastStmt = CS->body_back(); + if (!LastStmt) return; + + bool LoopIncrement, LastIncrement; + DeclRefExpr *LoopDRE, *LastDRE; + + if (!ProcessIterationStmt(S, Third, LoopIncrement, LoopDRE)) return; + if (!ProcessIterationStmt(S, LastStmt, LastIncrement, LastDRE)) return; + + // Check that the two statements are both increments or both decrements + // on the same varaible. + if (LoopIncrement != LastIncrement || + LoopDRE->getDecl() != LastDRE->getDecl()) return; + + if (ContinueFinder(S, Body).ContinueFound()) return; + + S.Diag(LastDRE->getLocation(), diag::warn_redundant_loop_iteration) + << LastDRE->getDecl() << LastIncrement; + S.Diag(LoopDRE->getLocation(), diag::note_loop_iteration_here) + << LoopIncrement; + } + } // end namespace StmtResult @@ -1447,6 +1539,7 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, } CheckForLoopConditionalStatement(*this, second.get(), third.get(), Body); + CheckForRedundantIteration(*this, third.get(), Body); ExprResult SecondResult(second.release()); VarDecl *ConditionVar = 0; @@ -1618,6 +1711,9 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, << First->getSourceRange()); FirstType = static_cast<Expr*>(First)->getType(); + if (FirstType.isConstQualified()) + Diag(ForLoc, diag::err_selector_element_const_type) + << FirstType << First->getSourceRange(); } if (!FirstType->isDependentType() && !FirstType->isObjCObjectPointerType() && @@ -1738,10 +1834,10 @@ StmtResult Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, Stmt *First, SourceLocation ColonLoc, Expr *Range, SourceLocation RParenLoc, BuildForRangeKind Kind) { - if (!First || !Range) + if (!First) return StmtError(); - if (ObjCEnumerationCollection(Range)) + if (Range && ObjCEnumerationCollection(Range)) return ActOnObjCForCollectionStmt(ForLoc, First, Range, RParenLoc); DeclStmt *DS = dyn_cast<DeclStmt>(First); @@ -1751,11 +1847,13 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, Diag(DS->getStartLoc(), diag::err_type_defined_in_for_range); return StmtError(); } - if (DS->getSingleDecl()->isInvalidDecl()) - return StmtError(); - if (DiagnoseUnexpandedParameterPack(Range, UPPC_Expression)) + Decl *LoopVar = DS->getSingleDecl(); + if (LoopVar->isInvalidDecl() || !Range || + DiagnoseUnexpandedParameterPack(Range, UPPC_Expression)) { + LoopVar->setInvalidDecl(); return StmtError(); + } // Build auto && __range = range-init SourceLocation RangeLoc = Range->getLocStart(); @@ -1763,15 +1861,20 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, Context.getAutoRRefDeductType(), "__range"); if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc, - diag::err_for_range_deduction_failure)) + diag::err_for_range_deduction_failure)) { + LoopVar->setInvalidDecl(); return StmtError(); + } // Claim the type doesn't contain auto: we've already done the checking. DeclGroupPtrTy RangeGroup = - BuildDeclaratorGroup((Decl**)&RangeVar, 1, /*TypeMayContainAuto=*/false); + BuildDeclaratorGroup(llvm::MutableArrayRef<Decl *>((Decl **)&RangeVar, 1), + /*TypeMayContainAuto=*/ false); StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc); - if (RangeDecl.isInvalid()) + if (RangeDecl.isInvalid()) { + LoopVar->setInvalidDecl(); return StmtError(); + } return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(), /*BeginEndDecl=*/0, /*Cond=*/0, /*Inc=*/0, DS, @@ -1900,6 +2003,22 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, Sema::BFRK_Rebuild); } +namespace { +/// RAII object to automatically invalidate a declaration if an error occurs. +struct InvalidateOnErrorScope { + InvalidateOnErrorScope(Sema &SemaRef, Decl *D, bool Enabled) + : Trap(SemaRef.Diags), D(D), Enabled(Enabled) {} + ~InvalidateOnErrorScope() { + if (Enabled && Trap.hasErrorOccurred()) + D->setInvalidDecl(); + } + + DiagnosticErrorTrap Trap; + Decl *D; + bool Enabled; +}; +} + /// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement. StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, @@ -1915,12 +2034,17 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, DeclStmt *LoopVarDS = cast<DeclStmt>(LoopVarDecl); VarDecl *LoopVar = cast<VarDecl>(LoopVarDS->getSingleDecl()); + // If we hit any errors, mark the loop variable as invalid if its type + // contains 'auto'. + InvalidateOnErrorScope Invalidate(*this, LoopVar, + LoopVar->getType()->isUndeducedType()); + StmtResult BeginEndDecl = BeginEnd; ExprResult NotEqExpr = Cond, IncrExpr = Inc; if (RangeVarType->isDependentType()) { // The range is implicitly used as a placeholder when it is dependent. - RangeVar->setUsed(); + RangeVar->markUsed(Context); // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill // them in properly when we instantiate the loop. @@ -1981,8 +2105,6 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, RangeLoc)); else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(UnqAT)) - // FIXME: Need to build an OpaqueValueExpr for this rather than - // recomputing it! BoundExpr = VAT->getSizeExpr(); else { // Can't be a DependentSizedArrayType or an IncompleteArrayType since @@ -2009,10 +2131,25 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, BeginVar, EndVar, ColonLoc, &CandidateSet, &BeginExpr, &EndExpr, &BEFFailure); - // If building the range failed, try dereferencing the range expression - // unless a diagnostic was issued or the end function is problematic. if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction && BEFFailure == BEF_begin) { + // If the range is being built from an array parameter, emit a + // a diagnostic that it is being treated as a pointer. + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Range)) { + if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { + QualType ArrayTy = PVD->getOriginalType(); + QualType PointerTy = PVD->getType(); + if (PointerTy->isPointerType() && ArrayTy->isArrayType()) { + Diag(Range->getLocStart(), diag::err_range_on_array_parameter) + << RangeLoc << PVD << ArrayTy << PointerTy; + Diag(PVD->getLocation(), diag::note_declared_at); + return StmtError(); + } + } + } + + // If building the range failed, try dereferencing the range expression + // unless a diagnostic was issued or the end function is problematic. StmtResult SR = RebuildForRangeWithDereference(*this, S, ForLoc, LoopVarDecl, ColonLoc, Range, RangeLoc, @@ -2048,7 +2185,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, Decl *BeginEndDecls[] = { BeginVar, EndVar }; // Claim the type doesn't contain auto: we've already done the checking. DeclGroupPtrTy BeginEndGroup = - BuildDeclaratorGroup(BeginEndDecls, 2, /*TypeMayContainAuto=*/false); + BuildDeclaratorGroup(llvm::MutableArrayRef<Decl *>(BeginEndDecls, 2), + /*TypeMayContainAuto=*/ false); BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc); const QualType BeginRefNonRefType = BeginType.getNonReferenceType(); @@ -2162,7 +2300,7 @@ StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, LabelDecl *TheDecl) { getCurFunction()->setHasBranchIntoScope(); - TheDecl->setUsed(); + TheDecl->markUsed(Context); return Owned(new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc)); } @@ -2356,28 +2494,51 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, return Res; } +/// \brief Determine whether the declared return type of the specified function +/// contains 'auto'. +static bool hasDeducedReturnType(FunctionDecl *FD) { + const FunctionProtoType *FPT = + FD->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>(); + return FPT->getResultType()->isUndeducedType(); +} + /// ActOnCapScopeReturnStmt - Utility routine to type-check return statements /// for capturing scopes. /// StmtResult Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // If this is the first return we've seen, infer the return type. - // [expr.prim.lambda]p4 in C++11; block literals follow a superset of those - // rules which allows multiple return statements. + // [expr.prim.lambda]p4 in C++11; block literals follow the same rules. CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction()); QualType FnRetType = CurCap->ReturnType; + LambdaScopeInfo *CurLambda = dyn_cast<LambdaScopeInfo>(CurCap); - // For blocks/lambdas with implicit return types, we check each return - // statement individually, and deduce the common return type when the block - // or lambda is completed. - if (CurCap->HasImplicitReturnType) { + if (CurLambda && hasDeducedReturnType(CurLambda->CallOperator)) { + // In C++1y, the return type may involve 'auto'. + // FIXME: Blocks might have a return type of 'auto' explicitly specified. + FunctionDecl *FD = CurLambda->CallOperator; + if (CurCap->ReturnType.isNull()) + CurCap->ReturnType = FD->getResultType(); + + AutoType *AT = CurCap->ReturnType->getContainedAutoType(); + assert(AT && "lost auto type from lambda return type"); + if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { + FD->setInvalidDecl(); + return StmtError(); + } + CurCap->ReturnType = FnRetType = FD->getResultType(); + } else if (CurCap->HasImplicitReturnType) { + // For blocks/lambdas with implicit return types, we check each return + // statement individually, and deduce the common return type when the block + // or lambda is completed. + // FIXME: Fold this into the 'auto' codepath above. if (RetValExp && !isa<InitListExpr>(RetValExp)) { ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp); if (Result.isInvalid()) return StmtError(); RetValExp = Result.take(); - if (!RetValExp->isTypeDependent()) + if (!CurContext->isDependentContext()) FnRetType = RetValExp->getType(); else FnRetType = CurCap->ReturnType = Context.DependentTy; @@ -2410,8 +2571,9 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { Diag(ReturnLoc, diag::err_return_in_captured_stmt) << CurRegion->getRegionName(); return StmtError(); } else { - LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CurCap); - if (LSI->CallOperator->getType()->getAs<FunctionType>()->getNoReturnAttr()){ + assert(CurLambda && "unknown kind of captured scope"); + if (CurLambda->CallOperator->getType()->getAs<FunctionType>() + ->getNoReturnAttr()) { Diag(ReturnLoc, diag::err_noreturn_lambda_has_return_expr); return StmtError(); } @@ -2492,7 +2654,24 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, IgnoreParens().castAs<FunctionProtoTypeLoc>().getResultLoc(); QualType Deduced; - if (RetExpr) { + if (RetExpr && isa<InitListExpr>(RetExpr)) { + // If the deduction is for a return statement and the initializer is + // a braced-init-list, the program is ill-formed. + Diag(RetExpr->getExprLoc(), + getCurLambda() ? diag::err_lambda_return_init_list + : diag::err_auto_fn_return_init_list) + << RetExpr->getSourceRange(); + return true; + } + + if (FD->isDependentContext()) { + // C++1y [dcl.spec.auto]p12: + // Return type deduction [...] occurs when the definition is + // instantiated even if the function body contains a return + // statement with a non-type-dependent operand. + assert(AT->isDeduced() && "should have deduced to dependent type"); + return false; + } else if (RetExpr) { // If the deduction is for a return statement and the initializer is // a braced-init-list, the program is ill-formed. if (isa<InitListExpr>(RetExpr)) { @@ -2533,10 +2712,18 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, // the program is ill-formed. if (AT->isDeduced() && !FD->isInvalidDecl()) { AutoType *NewAT = Deduced->getContainedAutoType(); - if (!Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) { - Diag(ReturnLoc, diag::err_auto_fn_different_deductions) - << (AT->isDecltypeAuto() ? 1 : 0) - << NewAT->getDeducedType() << AT->getDeducedType(); + if (!FD->isDependentContext() && + !Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) { + const LambdaScopeInfo *LambdaSI = getCurLambda(); + if (LambdaSI && LambdaSI->HasImplicitReturnType) { + Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible) + << NewAT->getDeducedType() << AT->getDeducedType() + << true /*IsLambda*/; + } else { + Diag(ReturnLoc, diag::err_auto_fn_different_deductions) + << (AT->isDecltypeAuto() ? 1 : 0) + << NewAT->getDeducedType() << AT->getDeducedType(); + } return true; } } else if (!FD->isInvalidDecl()) { @@ -2553,9 +2740,6 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) return StmtError(); - // FIXME: Unify this and C++1y auto function handling. In particular, we - // should allow 'return { 1, 2, 3 };' in a lambda to deduce - // 'std::initializer_list<int>'. if (isa<CapturingScopeInfo>(getCurFunction())) return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp); @@ -2580,13 +2764,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // FIXME: Add a flag to the ScopeInfo to indicate whether we're performing // deduction. - bool HasDependentReturnType = FnRetType->isDependentType(); if (getLangOpts().CPlusPlus1y) { if (AutoType *AT = FnRetType->getContainedAutoType()) { FunctionDecl *FD = cast<FunctionDecl>(CurContext); - if (CurContext->isDependentContext()) - HasDependentReturnType = true; - else if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { + if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { FD->setInvalidDecl(); return StmtError(); } else { @@ -2595,6 +2776,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } } + bool HasDependentReturnType = FnRetType->isDependentType(); + ReturnStmt *Result = 0; if (FnRetType->isVoidType()) { if (RetValExp) { @@ -2699,11 +2882,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // If we have a related result type, we need to implicitly // convert back to the formal result type. We can't pretend to // initialize the result again --- we might end double-retaining - // --- so instead we initialize a notional temporary; this can - // lead to less-than-great diagnostics, but this stage is much - // less likely to fail than the previous stage. + // --- so instead we initialize a notional temporary. if (!RelatedRetType.isNull()) { - Entity = InitializedEntity::InitializeTemporary(FnRetType); + Entity = InitializedEntity::InitializeRelatedResult(getCurMethodDecl(), + FnRetType); Res = PerformCopyInitialization(Entity, ReturnLoc, RetValExp); if (Res.isInvalid()) { // FIXME: Clean up temporaries here anyway? @@ -2886,18 +3068,16 @@ public: /// ActOnCXXTryBlock - Takes a try compound-statement and a number of /// handlers and creates a try statement from them. -StmtResult -Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, - MultiStmtArg RawHandlers) { +StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, + ArrayRef<Stmt *> Handlers) { // Don't report an error if 'try' is used in system headers. if (!getLangOpts().CXXExceptions && !getSourceManager().isInSystemHeader(TryLoc)) Diag(TryLoc, diag::err_exceptions_disabled) << "try"; - unsigned NumHandlers = RawHandlers.size(); + const unsigned NumHandlers = Handlers.size(); assert(NumHandlers > 0 && "The parser shouldn't call this if there are no handlers."); - Stmt **Handlers = RawHandlers.data(); SmallVector<TypeWithHandler, 8> TypesWithHandlers; @@ -2945,8 +3125,7 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, // Neither of these are explicitly forbidden, but every compiler detects them // and warns. - return Owned(CXXTryStmt::Create(Context, TryLoc, TryBlock, - llvm::makeArrayRef(Handlers, NumHandlers))); + return Owned(CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers)); } StmtResult @@ -3051,7 +3230,7 @@ static void buildCapturedStmtCaptureList( if (Cap->isThisCapture()) { Captures.push_back(CapturedStmt::Capture(Cap->getLocation(), CapturedStmt::VCK_This)); - CaptureInits.push_back(Cap->getCopyExpr()); + CaptureInits.push_back(Cap->getInitExpr()); continue; } @@ -3061,7 +3240,7 @@ static void buildCapturedStmtCaptureList( Captures.push_back(CapturedStmt::Capture(Cap->getLocation(), CapturedStmt::VCK_ByRef, Cap->getVariable())); - CaptureInits.push_back(Cap->getCopyExpr()); + CaptureInits.push_back(Cap->getInitExpr()); } } |