diff options
Diffstat (limited to 'lib/Sema/SemaStmt.cpp')
| -rw-r--r-- | lib/Sema/SemaStmt.cpp | 638 | 
1 files changed, 469 insertions, 169 deletions
| diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 0d1da4540eb3..5c72529caa8a 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -15,6 +15,7 @@  #include "clang/AST/ASTContext.h"  #include "clang/AST/ASTDiagnostic.h"  #include "clang/AST/CharUnits.h" +#include "clang/AST/CXXInheritance.h"  #include "clang/AST/DeclObjC.h"  #include "clang/AST/EvaluatedExprVisitor.h"  #include "clang/AST/ExprCXX.h" @@ -23,12 +24,14 @@  #include "clang/AST/StmtCXX.h"  #include "clang/AST/StmtObjC.h"  #include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeOrdering.h"  #include "clang/Lex/Preprocessor.h"  #include "clang/Sema/Initialization.h"  #include "clang/Sema/Lookup.h"  #include "clang/Sema/Scope.h"  #include "clang/Sema/ScopeInfo.h"  #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h"  #include "llvm/ADT/STLExtras.h"  #include "llvm/ADT/SmallPtrSet.h"  #include "llvm/ADT/SmallString.h" @@ -236,7 +239,9 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {      // is written in a macro body, only warn if it has the warn_unused_result      // attribute.      if (const Decl *FD = CE->getCalleeDecl()) { -      if (FD->hasAttr<WarnUnusedResultAttr>()) { +      const FunctionDecl *Func = dyn_cast<FunctionDecl>(FD); +      if (Func ? Func->hasUnusedResultAttr() +               : FD->hasAttr<WarnUnusedResultAttr>()) {          Diag(Loc, diag::warn_unused_result) << R1 << R2;          return;        } @@ -265,10 +270,6 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {          Diag(Loc, diag::warn_unused_result) << R1 << R2;          return;        } -      if (MD->isPropertyAccessor()) { -        Diag(Loc, diag::warn_unused_property_expr); -        return; -      }      }    } else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {      const Expr *Source = POE->getSyntacticForm(); @@ -687,26 +688,39 @@ static void checkCaseValue(Sema &S, SourceLocation Loc, const llvm::APSInt &Val,    }  } +typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy; +  /// Returns true if we should emit a diagnostic about this case expression not  /// being a part of the enum used in the switch controlling expression. -static bool ShouldDiagnoseSwitchCaseNotInEnum(const ASTContext &Ctx, +static bool ShouldDiagnoseSwitchCaseNotInEnum(const Sema &S,                                                const EnumDecl *ED, -                                              const Expr *CaseExpr) { -  // Don't warn if the 'case' expression refers to a static const variable of -  // the enum type. -  CaseExpr = CaseExpr->IgnoreParenImpCasts(); -  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CaseExpr)) { +                                              const Expr *CaseExpr, +                                              EnumValsTy::iterator &EI, +                                              EnumValsTy::iterator &EIEnd, +                                              const llvm::APSInt &Val) { +  bool FlagType = ED->hasAttr<FlagEnumAttr>(); + +  if (const DeclRefExpr *DRE = +          dyn_cast<DeclRefExpr>(CaseExpr->IgnoreParenImpCasts())) {      if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { -      if (!VD->hasGlobalStorage()) -        return true;        QualType VarType = VD->getType(); -      if (!VarType.isConstQualified()) -        return true; -      QualType EnumType = Ctx.getTypeDeclType(ED); -      if (Ctx.hasSameUnqualifiedType(EnumType, VarType)) +      QualType EnumType = S.Context.getTypeDeclType(ED); +      if (VD->hasGlobalStorage() && VarType.isConstQualified() && +          S.Context.hasSameUnqualifiedType(EnumType, VarType))          return false;      }    } + +  if (FlagType) { +    return !S.IsValueInFlagEnum(ED, Val, false); +  } else { +    while (EI != EIEnd && EI->first < Val) +      EI++; + +    if (EI != EIEnd && EI->first == Val) +      return false; +  } +    return true;  } @@ -897,12 +911,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,            if (PrevString == CurrString)              Diag(CaseVals[i].second->getLHS()->getLocStart(),                   diag::err_duplicate_case) << -                 (PrevString.empty() ? CaseValStr.str() : PrevString); +                 (PrevString.empty() ? StringRef(CaseValStr) : PrevString);            else              Diag(CaseVals[i].second->getLHS()->getLocStart(),                   diag::err_duplicate_case_differing_expr) << -                 (PrevString.empty() ? CaseValStr.str() : PrevString) << -                 (CurrString.empty() ? CaseValStr.str() : CurrString) << +                 (PrevString.empty() ? StringRef(CaseValStr) : PrevString) << +                 (CurrString.empty() ? StringRef(CaseValStr) : CurrString) <<                   CaseValStr;            Diag(CaseVals[i-1].second->getLHS()->getLocStart(), @@ -1046,8 +1060,6 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,      // If switch has default case, then ignore it.      if (!CaseListIsErroneous  && !HasConstantCond && ET) {        const EnumDecl *ED = ET->getDecl(); -      typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> -        EnumValsTy;        EnumValsTy EnumVals;        // Gather all enum values, set their type and sort them, @@ -1058,57 +1070,48 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,          EnumVals.push_back(std::make_pair(Val, EDI));        }        std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals); -      EnumValsTy::iterator EIend = +      auto EI = EnumVals.begin(), 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) { -          Expr *CaseExpr = CI->second->getLHS(); -          if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr)) -            Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) -              << CondTypeBeforePromotion; -        } +          CI != CaseVals.end(); CI++) { +        Expr *CaseExpr = CI->second->getLHS(); +        if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd, +                                              CI->first)) +          Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) +            << CondTypeBeforePromotion;        } +        // 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) { -          Expr *CaseExpr = RI->second->getLHS(); -          if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr)) -            Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) -              << CondTypeBeforePromotion; -        } +          RI != CaseRanges.end(); RI++) { +        Expr *CaseExpr = RI->second->getLHS(); +        if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd, +                                              RI->first)) +          Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) +            << CondTypeBeforePromotion;          llvm::APSInt Hi =            RI->second->getRHS()->EvaluateKnownConstInt(Context);          AdjustAPSInt(Hi, CondWidth, CondIsSigned); -        while (EI != EIend && EI->first < Hi) -          EI++; -        if (EI == EIend || EI->first != Hi) { -          Expr *CaseExpr = RI->second->getRHS(); -          if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr)) -            Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) -              << CondTypeBeforePromotion; -        } + +        CaseExpr = RI->second->getRHS(); +        if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd, +                                              Hi)) +          Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) +            << CondTypeBeforePromotion;        }        // Check which enum vals aren't in switch -      CaseValsTy::const_iterator CI = CaseVals.begin(); -      CaseRangesTy::const_iterator RI = CaseRanges.begin(); +      auto CI = CaseVals.begin(); +      auto RI = CaseRanges.begin();        bool hasCasesNotInSwitch = false;        SmallVector<DeclarationName,8> UnhandledNames; -      for (EI = EnumVals.begin(); EI != EIend; EI++){ +      for (EI = EnumVals.begin(); EI != EIEnd; EI++){          // Drop unneeded case values          while (CI != CaseVals.end() && CI->first < EI->first)            CI++; @@ -1135,29 +1138,15 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,          Diag(TheDefaultStmt->getDefaultLoc(), diag::warn_unreachable_default);        // Produce a nice diagnostic if multiple values aren't handled. -      switch (UnhandledNames.size()) { -      case 0: break; -      case 1: -        Diag(CondExpr->getExprLoc(), TheDefaultStmt -          ? diag::warn_def_missing_case1 : diag::warn_missing_case1) -          << UnhandledNames[0]; -        break; -      case 2: -        Diag(CondExpr->getExprLoc(), TheDefaultStmt -          ? diag::warn_def_missing_case2 : diag::warn_missing_case2) -          << UnhandledNames[0] << UnhandledNames[1]; -        break; -      case 3: -        Diag(CondExpr->getExprLoc(), TheDefaultStmt -          ? diag::warn_def_missing_case3 : diag::warn_missing_case3) -          << UnhandledNames[0] << UnhandledNames[1] << UnhandledNames[2]; -        break; -      default: -        Diag(CondExpr->getExprLoc(), TheDefaultStmt -          ? diag::warn_def_missing_cases : diag::warn_missing_cases) -          << (unsigned)UnhandledNames.size() -          << UnhandledNames[0] << UnhandledNames[1] << UnhandledNames[2]; -        break; +      if (!UnhandledNames.empty()) { +        DiagnosticBuilder DB = Diag(CondExpr->getExprLoc(), +                                    TheDefaultStmt ? diag::warn_def_missing_case +                                                   : diag::warn_missing_case) +                               << (int)UnhandledNames.size(); + +        for (size_t I = 0, E = std::min(UnhandledNames.size(), (size_t)3); +             I != E; ++I) +          DB << UnhandledNames[I];        }        if (!hasCasesNotInSwitch) @@ -1195,30 +1184,37 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,          llvm::APSInt RhsVal = SrcExpr->EvaluateKnownConstInt(Context);          AdjustAPSInt(RhsVal, DstWidth, DstIsSigned);          const EnumDecl *ED = ET->getDecl(); -        typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl *>, 64> -            EnumValsTy; -        EnumValsTy EnumVals; - -        // Gather all enum values, set their type and sort them, -        // allowing easier comparison with rhs constant. -        for (auto *EDI : ED->enumerators()) { -          llvm::APSInt Val = EDI->getInitVal(); -          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); - -        // 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_assignment) + +        if (ED->hasAttr<FlagEnumAttr>()) { +          if (!IsValueInFlagEnum(ED, RhsVal, true)) +            Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)                << DstType.getUnqualifiedType(); +        } else { +          typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl *>, 64> +              EnumValsTy; +          EnumValsTy EnumVals; + +          // Gather all enum values, set their type and sort them, +          // allowing easier comparison with rhs constant. +          for (auto *EDI : ED->enumerators()) { +            llvm::APSInt Val = EDI->getInitVal(); +            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); + +          // 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_assignment) +                << DstType.getUnqualifiedType(); +          }          }        }      } @@ -1832,6 +1828,15 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,  /// \return true if an error occurs.  static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,                                    SourceLocation Loc, int DiagID) { +  if (Decl->getType()->isUndeducedType()) { +    ExprResult Res = SemaRef.CorrectDelayedTyposInExpr(Init); +    if (!Res.isUsable()) { +      Decl->setInvalidDecl(); +      return true; +    } +    Init = Res.get(); +  } +    // Deduce the type for the iterator variable now rather than leaving it to    // AddInitializerToDecl, so we can produce a more suitable diagnostic.    QualType InitType; @@ -2368,6 +2373,156 @@ StmtResult Sema::FinishObjCForCollectionStmt(Stmt *S, Stmt *B) {    return S;  } +// Warn when the loop variable is a const reference that creates a copy. +// Suggest using the non-reference type for copies.  If a copy can be prevented +// suggest the const reference type that would do so. +// For instance, given "for (const &Foo : Range)", suggest +// "for (const Foo : Range)" to denote a copy is made for the loop.  If +// possible, also suggest "for (const &Bar : Range)" if this type prevents +// the copy altogether. +static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef, +                                                    const VarDecl *VD, +                                                    QualType RangeInitType) { +  const Expr *InitExpr = VD->getInit(); +  if (!InitExpr) +    return; + +  QualType VariableType = VD->getType(); + +  const MaterializeTemporaryExpr *MTE = +      dyn_cast<MaterializeTemporaryExpr>(InitExpr); + +  // No copy made. +  if (!MTE) +    return; + +  const Expr *E = MTE->GetTemporaryExpr()->IgnoreImpCasts(); + +  // Searching for either UnaryOperator for dereference of a pointer or +  // CXXOperatorCallExpr for handling iterators. +  while (!isa<CXXOperatorCallExpr>(E) && !isa<UnaryOperator>(E)) { +    if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(E)) { +      E = CCE->getArg(0); +    } else if (const CXXMemberCallExpr *Call = dyn_cast<CXXMemberCallExpr>(E)) { +      const MemberExpr *ME = cast<MemberExpr>(Call->getCallee()); +      E = ME->getBase(); +    } else { +      const MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(E); +      E = MTE->GetTemporaryExpr(); +    } +    E = E->IgnoreImpCasts(); +  } + +  bool ReturnsReference = false; +  if (isa<UnaryOperator>(E)) { +    ReturnsReference = true; +  } else { +    const CXXOperatorCallExpr *Call = cast<CXXOperatorCallExpr>(E); +    const FunctionDecl *FD = Call->getDirectCallee(); +    QualType ReturnType = FD->getReturnType(); +    ReturnsReference = ReturnType->isReferenceType(); +  } + +  if (ReturnsReference) { +    // Loop variable creates a temporary.  Suggest either to go with +    // non-reference loop variable to indiciate a copy is made, or +    // the correct time to bind a const reference. +    SemaRef.Diag(VD->getLocation(), diag::warn_for_range_const_reference_copy) +        << VD << VariableType << E->getType(); +    QualType NonReferenceType = VariableType.getNonReferenceType(); +    NonReferenceType.removeLocalConst(); +    QualType NewReferenceType = +        SemaRef.Context.getLValueReferenceType(E->getType().withConst()); +    SemaRef.Diag(VD->getLocStart(), diag::note_use_type_or_non_reference) +        << NonReferenceType << NewReferenceType << VD->getSourceRange(); +  } else { +    // The range always returns a copy, so a temporary is always created. +    // Suggest removing the reference from the loop variable. +    SemaRef.Diag(VD->getLocation(), diag::warn_for_range_variable_always_copy) +        << VD << RangeInitType; +    QualType NonReferenceType = VariableType.getNonReferenceType(); +    NonReferenceType.removeLocalConst(); +    SemaRef.Diag(VD->getLocStart(), diag::note_use_non_reference_type) +        << NonReferenceType << VD->getSourceRange(); +  } +} + +// Warns when the loop variable can be changed to a reference type to +// prevent a copy.  For instance, if given "for (const Foo x : Range)" suggest +// "for (const Foo &x : Range)" if this form does not make a copy. +static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef, +                                                const VarDecl *VD) { +  const Expr *InitExpr = VD->getInit(); +  if (!InitExpr) +    return; + +  QualType VariableType = VD->getType(); + +  if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitExpr)) { +    if (!CE->getConstructor()->isCopyConstructor()) +      return; +  } else if (const CastExpr *CE = dyn_cast<CastExpr>(InitExpr)) { +    if (CE->getCastKind() != CK_LValueToRValue) +      return; +  } else { +    return; +  } + +  // TODO: Determine a maximum size that a POD type can be before a diagnostic +  // should be emitted.  Also, only ignore POD types with trivial copy +  // constructors. +  if (VariableType.isPODType(SemaRef.Context)) +    return; + +  // Suggest changing from a const variable to a const reference variable +  // if doing so will prevent a copy. +  SemaRef.Diag(VD->getLocation(), diag::warn_for_range_copy) +      << VD << VariableType << InitExpr->getType(); +  SemaRef.Diag(VD->getLocStart(), diag::note_use_reference_type) +      << SemaRef.Context.getLValueReferenceType(VariableType) +      << VD->getSourceRange(); +} + +/// DiagnoseForRangeVariableCopies - Diagnose three cases and fixes for them. +/// 1) for (const foo &x : foos) where foos only returns a copy.  Suggest +///    using "const foo x" to show that a copy is made +/// 2) for (const bar &x : foos) where bar is a temporary intialized by bar. +///    Suggest either "const bar x" to keep the copying or "const foo& x" to +///    prevent the copy. +/// 3) for (const foo x : foos) where x is constructed from a reference foo. +///    Suggest "const foo &x" to prevent the copy. +static void DiagnoseForRangeVariableCopies(Sema &SemaRef, +                                           const CXXForRangeStmt *ForStmt) { +  if (SemaRef.Diags.isIgnored(diag::warn_for_range_const_reference_copy, +                              ForStmt->getLocStart()) && +      SemaRef.Diags.isIgnored(diag::warn_for_range_variable_always_copy, +                              ForStmt->getLocStart()) && +      SemaRef.Diags.isIgnored(diag::warn_for_range_copy, +                              ForStmt->getLocStart())) { +    return; +  } + +  const VarDecl *VD = ForStmt->getLoopVariable(); +  if (!VD) +    return; + +  QualType VariableType = VD->getType(); + +  if (VariableType->isIncompleteType()) +    return; + +  const Expr *InitExpr = VD->getInit(); +  if (!InitExpr) +    return; + +  if (VariableType->isReferenceType()) { +    DiagnoseForRangeReferenceVariableCopies(SemaRef, VD, +                                            ForStmt->getRangeInit()->getType()); +  } else if (VariableType.isConstQualified()) { +    DiagnoseForRangeConstVariableCopies(SemaRef, VD); +  } +} +  /// FinishCXXForRangeStmt - Attach the body to a C++0x for-range statement.  /// This is a separate step from ActOnCXXForRangeStmt because analysis of the  /// body cannot be performed until after the type of the range variable is @@ -2385,6 +2540,8 @@ StmtResult Sema::FinishCXXForRangeStmt(Stmt *S, Stmt *B) {    DiagnoseEmptyStmtBody(ForStmt->getRParenLoc(), B,                          diag::warn_empty_range_based_for_body); +  DiagnoseForRangeVariableCopies(*this, ForStmt); +    return S;  } @@ -2423,6 +2580,14 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,    return new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E);  } +static void CheckJumpOutOfSEHFinally(Sema &S, SourceLocation Loc, +                                     const Scope &DestScope) { +  if (!S.CurrentSEHFinally.empty() && +      DestScope.Contains(*S.CurrentSEHFinally.back())) { +    S.Diag(Loc, diag::warn_jump_out_of_seh_finally); +  } +} +  StmtResult  Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {    Scope *S = CurScope->getContinueParent(); @@ -2430,6 +2595,7 @@ Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {      // C99 6.8.6.2p1: A break shall appear only in or as a loop body.      return StmtError(Diag(ContinueLoc, diag::err_continue_not_in_loop));    } +  CheckJumpOutOfSEHFinally(*this, ContinueLoc, *S);    return new (Context) ContinueStmt(ContinueLoc);  } @@ -2444,6 +2610,7 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {    if (S->isOpenMPLoopScope())      return StmtError(Diag(BreakLoc, diag::err_omp_loop_cannot_use_stmt)                       << "break"); +  CheckJumpOutOfSEHFinally(*this, BreakLoc, *S);    return new (Context) BreakStmt(BreakLoc);  } @@ -2903,6 +3070,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,      CurScope->setNoNRVO();    } +  CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent()); +    return R;  } @@ -3179,7 +3348,7 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw,      Diag(AtLoc, diag::err_objc_exceptions_disabled) << "@throw";    if (!Throw) { -    // @throw without an expression designates a rethrow (which much occur +    // @throw without an expression designates a rethrow (which must occur      // in the context of an @catch clause).      Scope *AtCatchParent = CurScope;      while (AtCatchParent && !AtCatchParent->isAtCatchScope()) @@ -3251,35 +3420,112 @@ Sema::ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body) {  }  namespace { +class CatchHandlerType { +  QualType QT; +  unsigned IsPointer : 1; -class TypeWithHandler { -  QualType t; -  CXXCatchStmt *stmt; -public: -  TypeWithHandler(const QualType &type, CXXCatchStmt *statement) -  : t(type), stmt(statement) {} +  // This is a special constructor to be used only with DenseMapInfo's +  // getEmptyKey() and getTombstoneKey() functions. +  friend struct llvm::DenseMapInfo<CatchHandlerType>; +  enum Unique { ForDenseMap }; +  CatchHandlerType(QualType QT, Unique) : QT(QT), IsPointer(false) {} -  // An arbitrary order is fine as long as it places identical -  // types next to each other. -  bool operator<(const TypeWithHandler &y) const { -    if (t.getAsOpaquePtr() < y.t.getAsOpaquePtr()) -      return true; -    if (t.getAsOpaquePtr() > y.t.getAsOpaquePtr()) +public: +  /// Used when creating a CatchHandlerType from a handler type; will determine +  /// whether the type is a pointer or reference and will strip off the the top +  /// level pointer and cv-qualifiers. +  CatchHandlerType(QualType Q) : QT(Q), IsPointer(false) { +    if (QT->isPointerType()) +      IsPointer = true; + +    if (IsPointer || QT->isReferenceType()) +      QT = QT->getPointeeType(); +    QT = QT.getUnqualifiedType(); +  } + +  /// Used when creating a CatchHandlerType from a base class type; pretends the +  /// type passed in had the pointer qualifier, does not need to get an +  /// unqualified type. +  CatchHandlerType(QualType QT, bool IsPointer) +      : QT(QT), IsPointer(IsPointer) {} + +  QualType underlying() const { return QT; } +  bool isPointer() const { return IsPointer; } + +  friend bool operator==(const CatchHandlerType &LHS, +                         const CatchHandlerType &RHS) { +    // If the pointer qualification does not match, we can return early. +    if (LHS.IsPointer != RHS.IsPointer)        return false; -    else -      return getTypeSpecStartLoc() < y.getTypeSpecStartLoc(); +    // Otherwise, check the underlying type without cv-qualifiers. +    return LHS.QT == RHS.QT; +  } +}; +} // namespace + +namespace llvm { +template <> struct DenseMapInfo<CatchHandlerType> { +  static CatchHandlerType getEmptyKey() { +    return CatchHandlerType(DenseMapInfo<QualType>::getEmptyKey(), +                       CatchHandlerType::ForDenseMap);    } -  bool operator==(const TypeWithHandler& other) const { -    return t == other.t; +  static CatchHandlerType getTombstoneKey() { +    return CatchHandlerType(DenseMapInfo<QualType>::getTombstoneKey(), +                       CatchHandlerType::ForDenseMap);    } -  CXXCatchStmt *getCatchStmt() const { return stmt; } -  SourceLocation getTypeSpecStartLoc() const { -    return stmt->getExceptionDecl()->getTypeSpecStartLoc(); +  static unsigned getHashValue(const CatchHandlerType &Base) { +    return DenseMapInfo<QualType>::getHashValue(Base.underlying());    } + +  static bool isEqual(const CatchHandlerType &LHS, +                      const CatchHandlerType &RHS) { +    return LHS == RHS; +  } +}; + +// It's OK to treat CatchHandlerType as a POD type. +template <> struct isPodLike<CatchHandlerType> { +  static const bool value = true;  }; +} + +namespace { +class CatchTypePublicBases { +  ASTContext &Ctx; +  const llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> &TypesToCheck; +  const bool CheckAgainstPointer; + +  CXXCatchStmt *FoundHandler; +  CanQualType FoundHandlerType; +public: +  CatchTypePublicBases( +      ASTContext &Ctx, +      const llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> &T, bool C) +      : Ctx(Ctx), TypesToCheck(T), CheckAgainstPointer(C), +        FoundHandler(nullptr) {} + +  CXXCatchStmt *getFoundHandler() const { return FoundHandler; } +  CanQualType getFoundHandlerType() const { return FoundHandlerType; } + +  static bool FindPublicBasesOfType(const CXXBaseSpecifier *S, CXXBasePath &, +                                    void *User) { +    auto &PBOT = *reinterpret_cast<CatchTypePublicBases *>(User); +    if (S->getAccessSpecifier() == AccessSpecifier::AS_public) { +      CatchHandlerType Check(S->getType(), PBOT.CheckAgainstPointer); +      auto M = PBOT.TypesToCheck; +      auto I = M.find(Check); +      if (I != M.end()) { +        PBOT.FoundHandler = I->second; +        PBOT.FoundHandlerType = PBOT.Ctx.getCanonicalType(S->getType()); +        return true; +      } +    } +    return false; +  } +};  }  /// ActOnCXXTryBlock - Takes a try compound-statement and a number of @@ -3289,74 +3535,120 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,    // 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"; +    Diag(TryLoc, diag::err_exceptions_disabled) << "try";    if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())      Diag(TryLoc, diag::err_omp_simd_region_cannot_use_stmt) << "try"; +  sema::FunctionScopeInfo *FSI = getCurFunction(); + +  // C++ try is incompatible with SEH __try. +  if (!getLangOpts().Borland && FSI->FirstSEHTryLoc.isValid()) { +    Diag(TryLoc, diag::err_mixing_cxx_try_seh_try); +    Diag(FSI->FirstSEHTryLoc, diag::note_conflicting_try_here) << "'__try'"; +  } +    const unsigned NumHandlers = Handlers.size(); -  assert(NumHandlers > 0 && +  assert(!Handlers.empty() &&           "The parser shouldn't call this if there are no handlers."); -  SmallVector<TypeWithHandler, 8> TypesWithHandlers; - +  llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> HandledTypes;    for (unsigned i = 0; i < NumHandlers; ++i) { -    CXXCatchStmt *Handler = cast<CXXCatchStmt>(Handlers[i]); -    if (!Handler->getExceptionDecl()) { -      if (i < NumHandlers - 1) -        return StmtError(Diag(Handler->getLocStart(), -                              diag::err_early_catch_all)); +    CXXCatchStmt *H = cast<CXXCatchStmt>(Handlers[i]); +    // Diagnose when the handler is a catch-all handler, but it isn't the last +    // handler for the try block. [except.handle]p5. Also, skip exception +    // declarations that are invalid, since we can't usefully report on them. +    if (!H->getExceptionDecl()) { +      if (i < NumHandlers - 1) +        return StmtError(Diag(H->getLocStart(), diag::err_early_catch_all)); +      continue; +    } else if (H->getExceptionDecl()->isInvalidDecl())        continue; -    } - -    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()); - -    TypeWithHandler prev = TypesWithHandlers[0]; -    for (unsigned i = 1; i < TypesWithHandlers.size(); ++i) { -      TypeWithHandler curr = TypesWithHandlers[i]; -      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(); +    // Walk the type hierarchy to diagnose when this type has already been +    // handled (duplication), or cannot be handled (derivation inversion). We +    // ignore top-level cv-qualifiers, per [except.handle]p3 +    CatchHandlerType HandlerCHT = +        (QualType)Context.getCanonicalType(H->getCaughtType()); + +    // We can ignore whether the type is a reference or a pointer; we need the +    // underlying declaration type in order to get at the underlying record +    // decl, if there is one. +    QualType Underlying = HandlerCHT.underlying(); +    if (auto *RD = Underlying->getAsCXXRecordDecl()) { +      if (!RD->hasDefinition()) +        continue; +      // Check that none of the public, unambiguous base classes are in the +      // map ([except.handle]p1). Give the base classes the same pointer +      // qualification as the original type we are basing off of. This allows +      // comparison against the handler type using the same top-level pointer +      // as the original type. +      CXXBasePaths Paths; +      Paths.setOrigin(RD); +      CatchTypePublicBases CTPB(Context, HandledTypes, HandlerCHT.isPointer()); +      if (RD->lookupInBases(CatchTypePublicBases::FindPublicBasesOfType, &CTPB, +                            Paths)) { +        const CXXCatchStmt *Problem = CTPB.getFoundHandler(); +        if (!Paths.isAmbiguous(CTPB.getFoundHandlerType())) { +          Diag(H->getExceptionDecl()->getTypeSpecStartLoc(), +               diag::warn_exception_caught_by_earlier_handler) +              << H->getCaughtType(); +          Diag(Problem->getExceptionDecl()->getTypeSpecStartLoc(), +                diag::note_previous_exception_handler) +              << Problem->getCaughtType(); +        }        } +    } -      prev = curr; +    // Add the type the list of ones we have handled; diagnose if we've already +    // handled it. +    auto R = HandledTypes.insert(std::make_pair(H->getCaughtType(), H)); +    if (!R.second) { +      const CXXCatchStmt *Problem = R.first->second; +      Diag(H->getExceptionDecl()->getTypeSpecStartLoc(), +           diag::warn_exception_caught_by_earlier_handler) +          << H->getCaughtType(); +      Diag(Problem->getExceptionDecl()->getTypeSpecStartLoc(), +           diag::note_previous_exception_handler) +          << Problem->getCaughtType();      }    } -  getCurFunction()->setHasBranchProtectedScope(); - -  // 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. +  FSI->setHasCXXTry(TryLoc);    return CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers);  } -StmtResult -Sema::ActOnSEHTryBlock(bool IsCXXTry, -                       SourceLocation TryLoc, -                       Stmt *TryBlock, -                       Stmt *Handler) { +StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, +                                  Stmt *TryBlock, Stmt *Handler) {    assert(TryBlock && Handler); -  getCurFunction()->setHasBranchProtectedScope(); +  sema::FunctionScopeInfo *FSI = getCurFunction(); + +  // SEH __try is incompatible with C++ try. Borland appears to support this, +  // however. +  if (!getLangOpts().Borland) { +    if (FSI->FirstCXXTryLoc.isValid()) { +      Diag(TryLoc, diag::err_mixing_cxx_try_seh_try); +      Diag(FSI->FirstCXXTryLoc, diag::note_conflicting_try_here) << "'try'"; +    } +  } + +  FSI->setHasSEHTry(TryLoc); -  return SEHTryStmt::Create(Context,IsCXXTry,TryLoc,TryBlock,Handler); +  // Reject __try in Obj-C methods, blocks, and captured decls, since we don't +  // track if they use SEH. +  DeclContext *DC = CurContext; +  while (DC && !DC->isFunctionOrMethod()) +    DC = DC->getParent(); +  FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(DC); +  if (FD) +    FD->setUsesSEHTry(true); +  else +    Diag(TryLoc, diag::err_seh_try_outside_functions); + +  return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler);  }  StmtResult @@ -3374,11 +3666,18 @@ Sema::ActOnSEHExceptBlock(SourceLocation Loc,    return SEHExceptStmt::Create(Context,Loc,FilterExpr,Block);  } -StmtResult -Sema::ActOnSEHFinallyBlock(SourceLocation Loc, -                           Stmt *Block) { +void Sema::ActOnStartSEHFinallyBlock() { +  CurrentSEHFinally.push_back(CurScope); +} + +void Sema::ActOnAbortSEHFinallyBlock() { +  CurrentSEHFinally.pop_back(); +} + +StmtResult Sema::ActOnFinishSEHFinallyBlock(SourceLocation Loc, Stmt *Block) {    assert(Block); -  return SEHFinallyStmt::Create(Context,Loc,Block); +  CurrentSEHFinally.pop_back(); +  return SEHFinallyStmt::Create(Context, Loc, Block);  }  StmtResult @@ -3388,6 +3687,7 @@ Sema::ActOnSEHLeaveStmt(SourceLocation Loc, Scope *CurScope) {      SEHTryParent = SEHTryParent->getParent();    if (!SEHTryParent)      return StmtError(Diag(Loc, diag::err_ms___leave_not_in___try)); +  CheckJumpOutOfSEHFinally(*this, Loc, *SEHTryParent);    return new (Context) SEHLeaveStmt(Loc);  } | 
