diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3101,6 +3101,26 @@ bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg); + /// Try to perform the initialization of a potentially-movable value, + /// which is the operand to a return or throw statement. + /// + /// This routine implements C++14 [class.copy]p32, which attempts to treat + /// returned lvalues as rvalues in certain cases (to prefer move + /// construction), then falls back to treating them as lvalues if that failed. + /// + /// \param ConvertingConstructorsOnly If true, follow [class.copy]p32 and + /// reject resolutions that find non-constructors, such as derived-to-base + /// conversions or `operator T()&&` member functions. If false, do consider + /// such conversion sequences. + /// + /// \param Res We will fill this in if move-initialization was possible. + /// If move-initialization is not possible, such that we must fall back to + /// treating the operand as an lvalue, we will leave Res in its original + /// invalid state. + void TryMoveInitialization(const InitializedEntity &Entity, + const VarDecl *NRVOCandidate, QualType ResultType, + Expr *&Value, bool ConvertingConstructorsOnly, + ExprResult &Res); ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity, const VarDecl *NRVOCandidate, QualType ResultType, @@ -4306,9 +4326,23 @@ Stmt *InitStmt, ConditionResult Cond, Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); + /// Check the specified case value is in range for the given unpromoted switch + /// type. + void CheckCaseValue(SourceLocation Loc, const llvm::APSInt &Val, + unsigned UnpromotedWidth, bool UnpromotedSign); StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Stmt *InitStmt, ConditionResult Cond); + using EnumValsTy = + SmallVector, 64>; + /// 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. + bool ShouldDiagnoseSwitchCaseNotInEnum(const EnumDecl *ED, + const Expr *CaseExpr, + EnumValsTy::iterator &EI, + EnumValsTy::iterator &EIEnd, + const llvm::APSInt &Val); + void CheckEnumTypesInSwitchStmt(const Expr *Cond, const Expr *Case); StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *Body); StmtResult ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond, @@ -4329,6 +4363,14 @@ StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, Stmt *First, Expr *collection, SourceLocation RParenLoc); + // 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. + void DiagnoseForRangeReferenceVariableCopies(const VarDecl *VD, + QualType RangeInitType); StmtResult FinishObjCForCollectionStmt(Stmt *ForCollection, Stmt *Body); enum BuildForRangeKind { @@ -4342,6 +4384,9 @@ BFRK_Check }; + /// Build a variable declaration for a for-range statement. + VarDecl *BuildForRangeVarDecl(SourceLocation Loc, QualType Type, + StringRef Name); StmtResult ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *InitStmt, @@ -4358,6 +4403,19 @@ Stmt *LoopVarDecl, SourceLocation RParenLoc, BuildForRangeKind Kind); + // 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. + void DiagnoseForRangeConstVariableCopies(const VarDecl *VD); + /// 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 initialized 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. + void DiagnoseForRangeVariableCopies(const CXXForRangeStmt *ForStmt); StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body); StmtResult ActOnGotoStmt(SourceLocation GotoLoc, @@ -4366,9 +4424,14 @@ StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, Expr *DestExp); + void CheckJumpOutOfSEHFinally(SourceLocation Loc, const Scope &DestScope); StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope); StmtResult ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope); + bool + BuildCapturedStmtCaptureList(sema::CapturedRegionScopeInfo *RSI, + SmallVectorImpl &Captures, + SmallVectorImpl &CaptureInits); void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, CapturedRegionKind Kind, unsigned NumParams); typedef std::pair CapturedParamNameType; @@ -4490,6 +4553,14 @@ /// of it. void MarkUnusedFileScopedDecl(const DeclaratorDecl *D); + /// Diagnose unused comparisons, both builtin and overloaded operators. + /// For '==' and '!=', suggest fixits for '=' or '|='. + /// + /// Adding a cast to void (or other expression wrappers) will prevent the + /// warning from firing. + bool DiagnoseUnusedComparison(const Expr *E); + bool DiagnoseNoDiscard(const WarnUnusedResultAttr *A, SourceLocation Loc, + SourceRange R1, SourceRange R2, bool IsCtor); /// DiagnoseUnusedExprResult - If the statement passed in is an expression /// whose result is unused, warn. void DiagnoseUnusedExprResult(const Stmt *S); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -120,12 +120,7 @@ } } -/// Diagnose unused comparisons, both builtin and overloaded operators. -/// For '==' and '!=', suggest fixits for '=' or '|='. -/// -/// Adding a cast to void (or other expression wrappers) will prevent the -/// warning from firing. -static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) { +bool Sema::DiagnoseUnusedComparison(const Expr *E) { SourceLocation Loc; bool CanAssign; enum { Equality, Inequality, Relational, ThreeWay } Kind; @@ -176,43 +171,41 @@ // Suppress warnings when the operator, suspicious as it may be, comes from // a macro expansion. - if (S.SourceMgr.isMacroBodyExpansion(Loc)) + if (SourceMgr.isMacroBodyExpansion(Loc)) return false; - S.Diag(Loc, diag::warn_unused_comparison) - << (unsigned)Kind << E->getSourceRange(); + Diag(Loc, diag::warn_unused_comparison) + << (unsigned)Kind << E->getSourceRange(); // If the LHS is a plausible entity to assign to, provide a fixit hint to // correct common typos. if (CanAssign) { if (Kind == Inequality) - S.Diag(Loc, diag::note_inequality_comparison_to_or_assign) - << FixItHint::CreateReplacement(Loc, "|="); + Diag(Loc, diag::note_inequality_comparison_to_or_assign) + << FixItHint::CreateReplacement(Loc, "|="); else if (Kind == Equality) - S.Diag(Loc, diag::note_equality_comparison_to_assign) - << FixItHint::CreateReplacement(Loc, "="); + Diag(Loc, diag::note_equality_comparison_to_assign) + << FixItHint::CreateReplacement(Loc, "="); } return true; } -static bool DiagnoseNoDiscard(Sema &S, const WarnUnusedResultAttr *A, - SourceLocation Loc, SourceRange R1, - SourceRange R2, bool IsCtor) { +bool Sema::DiagnoseNoDiscard(const WarnUnusedResultAttr *A, SourceLocation Loc, + SourceRange R1, SourceRange R2, bool IsCtor) { if (!A) return false; StringRef Msg = A->getMessage(); if (Msg.empty()) { if (IsCtor) - return S.Diag(Loc, diag::warn_unused_constructor) << A << R1 << R2; - return S.Diag(Loc, diag::warn_unused_result) << A << R1 << R2; + return Diag(Loc, diag::warn_unused_constructor) << A << R1 << R2; + return Diag(Loc, diag::warn_unused_result) << A << R1 << R2; } if (IsCtor) - return S.Diag(Loc, diag::warn_unused_constructor_msg) << A << Msg << R1 - << R2; - return S.Diag(Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2; + return Diag(Loc, diag::warn_unused_constructor_msg) << A << Msg << R1 << R2; + return Diag(Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2; } void Sema::DiagnoseUnusedExprResult(const Stmt *S) { @@ -269,7 +262,7 @@ if (const CXXBindTemporaryExpr *TempExpr = dyn_cast(E)) E = TempExpr->getSubExpr(); - if (DiagnoseUnusedComparison(*this, E)) + if (DiagnoseUnusedComparison(E)) return; E = WarnExpr; @@ -282,8 +275,8 @@ if (E->getType()->isVoidType()) return; - if (DiagnoseNoDiscard(*this, cast_or_null( - CE->getUnusedResultAttr(Context)), + if (DiagnoseNoDiscard(cast_or_null( + CE->getUnusedResultAttr(Context)), Loc, R1, R2, /*isCtor=*/false)) return; @@ -307,14 +300,14 @@ if (const CXXConstructorDecl *Ctor = CE->getConstructor()) { const auto *A = Ctor->getAttr(); A = A ? A : Ctor->getParent()->getAttr(); - if (DiagnoseNoDiscard(*this, A, Loc, R1, R2, /*isCtor=*/true)) + if (DiagnoseNoDiscard(A, Loc, R1, R2, /*isCtor=*/true)) return; } } else if (const auto *ILE = dyn_cast(E)) { if (const TagDecl *TD = ILE->getType()->getAsTagDecl()) { - if (DiagnoseNoDiscard(*this, TD->getAttr(), Loc, R1, - R2, /*isCtor=*/false)) + if (DiagnoseNoDiscard(TD->getAttr(), Loc, R1, R2, + /*isCtor=*/false)) return; } } else if (ShouldSuppress) @@ -328,8 +321,8 @@ } const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD) { - if (DiagnoseNoDiscard(*this, MD->getAttr(), Loc, R1, - R2, /*isCtor=*/false)) + if (DiagnoseNoDiscard(MD->getAttr(), Loc, R1, R2, + /*isCtor=*/false)) return; } } else if (const PseudoObjectExpr *POE = dyn_cast(E)) { @@ -762,12 +755,10 @@ Val.setIsSigned(IsSigned); } -/// Check the specified case value is in range for the given unpromoted switch -/// type. -static void checkCaseValue(Sema &S, SourceLocation Loc, const llvm::APSInt &Val, - unsigned UnpromotedWidth, bool UnpromotedSign) { +void Sema::CheckCaseValue(SourceLocation Loc, const llvm::APSInt &Val, + unsigned UnpromotedWidth, bool UnpromotedSign) { // In C++11 onwards, this is checked by the language rules. - if (S.getLangOpts().CPlusPlus11) + if (getLangOpts().CPlusPlus11) return; // If the case value was signed and negative and the switch expression is @@ -781,21 +772,16 @@ // type versus "switch expression cannot have this value". Use proper // IntRange checking rather than just looking at the unpromoted type here. if (ConvVal != Val) - S.Diag(Loc, diag::warn_case_value_overflow) << Val.toString(10) - << ConvVal.toString(10); + Diag(Loc, diag::warn_case_value_overflow) + << Val.toString(10) << ConvVal.toString(10); } } -typedef SmallVector, 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 Sema &S, - const EnumDecl *ED, - const Expr *CaseExpr, - EnumValsTy::iterator &EI, - EnumValsTy::iterator &EIEnd, - const llvm::APSInt &Val) { +bool Sema::ShouldDiagnoseSwitchCaseNotInEnum(const EnumDecl *ED, + const Expr *CaseExpr, + EnumValsTy::iterator &EI, + EnumValsTy::iterator &EIEnd, + const llvm::APSInt &Val) { if (!ED->isClosed()) return false; @@ -803,15 +789,15 @@ dyn_cast(CaseExpr->IgnoreParenImpCasts())) { if (const VarDecl *VD = dyn_cast(DRE->getDecl())) { QualType VarType = VD->getType(); - QualType EnumType = S.Context.getTypeDeclType(ED); + QualType EnumType = Context.getTypeDeclType(ED); if (VD->hasGlobalStorage() && VarType.isConstQualified() && - S.Context.hasSameUnqualifiedType(EnumType, VarType)) + Context.hasSameUnqualifiedType(EnumType, VarType)) return false; } } if (ED->hasAttr()) - return !S.IsValueInFlagEnum(ED, Val, false); + return !IsValueInFlagEnum(ED, Val, false); while (EI != EIEnd && EI->first < Val) EI++; @@ -822,8 +808,7 @@ return true; } -static void checkEnumTypesInSwitchStmt(Sema &S, const Expr *Cond, - const Expr *Case) { +void Sema::CheckEnumTypesInSwitchStmt(const Expr *Cond, const Expr *Case) { QualType CondType = Cond->getType(); QualType CaseType = Case->getType(); @@ -840,10 +825,10 @@ !CaseEnumType->getDecl()->getTypedefNameForAnonDecl()) return; - if (S.Context.hasSameUnqualifiedType(CondType, CaseType)) + if (Context.hasSameUnqualifiedType(CondType, CaseType)) return; - S.Diag(Case->getExprLoc(), diag::warn_comparison_of_mixed_enum_types_switch) + Diag(Case->getExprLoc(), diag::warn_comparison_of_mixed_enum_types_switch) << CondType << CaseType << Cond->getSourceRange() << Case->getSourceRange(); } @@ -941,12 +926,11 @@ // Check the unconverted value is within the range of possible values of // the switch expression. - checkCaseValue(*this, Lo->getBeginLoc(), LoVal, CondWidthBeforePromotion, + CheckCaseValue(Lo->getBeginLoc(), LoVal, CondWidthBeforePromotion, CondIsSignedBeforePromotion); // FIXME: This duplicates the check performed for warn_not_in_enum below. - checkEnumTypesInSwitchStmt(*this, CondExprBeforePromotion, - LoBeforePromotion); + CheckEnumTypesInSwitchStmt(CondExprBeforePromotion, LoBeforePromotion); // Convert the value to the same width/sign as the condition. AdjustAPSInt(LoVal, CondWidth, CondIsSigned); @@ -1044,8 +1028,8 @@ // Check the unconverted value is within the range of possible values of // the switch expression. - checkCaseValue(*this, Hi->getBeginLoc(), HiVal, - CondWidthBeforePromotion, CondIsSignedBeforePromotion); + CheckCaseValue(Hi->getBeginLoc(), HiVal, CondWidthBeforePromotion, + CondIsSignedBeforePromotion); // Convert the value to the same width/sign as the condition. AdjustAPSInt(HiVal, CondWidth, CondIsSigned); @@ -1155,7 +1139,7 @@ for (CaseValsTy::const_iterator CI = CaseVals.begin(); CI != CaseVals.end(); CI++) { Expr *CaseExpr = CI->second->getLHS(); - if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd, + if (ShouldDiagnoseSwitchCaseNotInEnum(ED, CaseExpr, EI, EIEnd, CI->first)) Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) << CondTypeBeforePromotion; @@ -1166,7 +1150,7 @@ for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); RI != CaseRanges.end(); RI++) { Expr *CaseExpr = RI->second->getLHS(); - if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd, + if (ShouldDiagnoseSwitchCaseNotInEnum(ED, CaseExpr, EI, EIEnd, RI->first)) Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) << CondTypeBeforePromotion; @@ -1176,8 +1160,7 @@ AdjustAPSInt(Hi, CondWidth, CondIsSigned); CaseExpr = RI->second->getRHS(); - if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd, - Hi)) + if (ShouldDiagnoseSwitchCaseNotInEnum(ED, CaseExpr, EI, EIEnd, Hi)) Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) << CondTypeBeforePromotion; } @@ -2058,20 +2041,19 @@ << BEF << IsTemplate << Description << E->getType(); } -/// Build a variable declaration for a for-range statement. -VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc, - QualType Type, StringRef Name) { - DeclContext *DC = SemaRef.CurContext; - IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); - TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); - VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, - TInfo, SC_None); +} // namespace + +VarDecl *Sema::BuildForRangeVarDecl(SourceLocation Loc, QualType Type, + StringRef Name) { + DeclContext *DC = CurContext; + IdentifierInfo *II = &PP.getIdentifierTable().get(Name); + TypeSourceInfo *TInfo = Context.getTrivialTypeSourceInfo(Type, Loc); + VarDecl *Decl = + VarDecl::Create(Context, DC, Loc, Loc, II, Type, TInfo, SC_None); Decl->setImplicit(); return Decl; } -} - static bool ObjCEnumerationCollection(Expr *Collection) { return !Collection->isTypeDependent() && Collection->getType()->getAs() != nullptr; @@ -2137,9 +2119,9 @@ // Divide by 2, since the variables are in the inner scope (loop body). const auto DepthStr = std::to_string(S->getDepth() / 2); SourceLocation RangeLoc = Range->getBeginLoc(); - VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc, - Context.getAutoRRefDeductType(), - std::string("__range") + DepthStr); + VarDecl *RangeVar = + BuildForRangeVarDecl(RangeLoc, Context.getAutoRRefDeductType(), + std::string("__range") + DepthStr); if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc, diag::err_for_range_deduction_failure)) { LoopVar->setInvalidDecl(); @@ -2432,9 +2414,9 @@ // Build auto __begin = begin-expr, __end = end-expr. // Divide by 2, since the variables are in the inner scope (loop body). const auto DepthStr = std::to_string(S->getDepth() / 2); - VarDecl *BeginVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType, + VarDecl *BeginVar = BuildForRangeVarDecl(ColonLoc, AutoType, std::string("__begin") + DepthStr); - VarDecl *EndVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType, + VarDecl *EndVar = BuildForRangeVarDecl(ColonLoc, AutoType, std::string("__end") + DepthStr); // Build begin-expr and end-expr and attach to __begin and __end variables. @@ -2702,16 +2684,8 @@ 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) { +void Sema::DiagnoseForRangeReferenceVariableCopies(const VarDecl *VD, + QualType RangeInitType) { const Expr *InitExpr = VD->getInit(); if (!InitExpr) return; @@ -2748,7 +2722,7 @@ QualType ReferenceReturnType; if (isa(E)) { - ReferenceReturnType = SemaRef.Context.getLValueReferenceType(E->getType()); + ReferenceReturnType = Context.getLValueReferenceType(E->getType()); } else { const CXXOperatorCallExpr *Call = cast(E); const FunctionDecl *FD = Call->getDirectCallee(); @@ -2761,14 +2735,14 @@ // Loop variable creates a temporary. Suggest either to go with // non-reference loop variable to indicate a copy is made, or // the correct type to bind a const reference. - SemaRef.Diag(VD->getLocation(), - diag::warn_for_range_const_ref_binds_temp_built_from_ref) + Diag(VD->getLocation(), + diag::warn_for_range_const_ref_binds_temp_built_from_ref) << VD << VariableType << ReferenceReturnType; QualType NonReferenceType = VariableType.getNonReferenceType(); NonReferenceType.removeLocalConst(); QualType NewReferenceType = - SemaRef.Context.getLValueReferenceType(E->getType().withConst()); - SemaRef.Diag(VD->getBeginLoc(), diag::note_use_type_or_non_reference) + Context.getLValueReferenceType(E->getType().withConst()); + Diag(VD->getBeginLoc(), diag::note_use_type_or_non_reference) << NonReferenceType << NewReferenceType << VD->getSourceRange() << FixItHint::CreateRemoval(VD->getTypeSpecEndLoc()); } else if (!VariableType->isRValueReferenceType()) { @@ -2776,11 +2750,11 @@ // Suggest removing the reference from the loop variable. // If the type is a rvalue reference do not warn since that changes the // semantic of the code. - SemaRef.Diag(VD->getLocation(), diag::warn_for_range_ref_binds_ret_temp) + Diag(VD->getLocation(), diag::warn_for_range_ref_binds_ret_temp) << VD << RangeInitType; QualType NonReferenceType = VariableType.getNonReferenceType(); NonReferenceType.removeLocalConst(); - SemaRef.Diag(VD->getBeginLoc(), diag::note_use_non_reference_type) + Diag(VD->getBeginLoc(), diag::note_use_non_reference_type) << NonReferenceType << VD->getSourceRange() << FixItHint::CreateRemoval(VD->getTypeSpecEndLoc()); } @@ -2795,17 +2769,11 @@ return false; } -// 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) { +void Sema::DiagnoseForRangeConstVariableCopies(const VarDecl *VD) { const Expr *InitExpr = VD->getInit(); if (!InitExpr) return; - QualType VariableType = VD->getType(); - if (const CXXConstructExpr *CE = dyn_cast(InitExpr)) { if (!CE->getConstructor()->isCopyConstructor()) return; @@ -2819,44 +2787,30 @@ // Small trivially copyable types are cheap to copy. Do not emit the // diagnostic for these instances. 64 bytes is a common size of a cache line. // (The function `getTypeSize` returns the size in bits.) - ASTContext &Ctx = SemaRef.Context; - if (Ctx.getTypeSize(VariableType) <= 64 * 8 && - (VariableType.isTriviallyCopyableType(Ctx) || + QualType VariableType = VD->getType(); + if (Context.getTypeSize(VariableType) <= 64 * 8 && + (VariableType.isTriviallyCopyableType(Context) || hasTrivialABIAttr(VariableType))) 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; - SemaRef.Diag(VD->getBeginLoc(), diag::note_use_reference_type) - << SemaRef.Context.getLValueReferenceType(VariableType) - << VD->getSourceRange() + Diag(VD->getLocation(), diag::warn_for_range_copy) << VD << VariableType; + Diag(VD->getBeginLoc(), diag::note_use_reference_type) + << Context.getLValueReferenceType(VariableType) << VD->getSourceRange() << FixItHint::CreateInsertion(VD->getLocation(), "&"); } -/// 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 initialized 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.inTemplateInstantiation()) +void Sema::DiagnoseForRangeVariableCopies(const CXXForRangeStmt *ForStmt) { + if (inTemplateInstantiation()) return; - if (SemaRef.Diags.isIgnored( - diag::warn_for_range_const_ref_binds_temp_built_from_ref, - ForStmt->getBeginLoc()) && - SemaRef.Diags.isIgnored(diag::warn_for_range_ref_binds_ret_temp, - ForStmt->getBeginLoc()) && - SemaRef.Diags.isIgnored(diag::warn_for_range_copy, - ForStmt->getBeginLoc())) { + if (Diags.isIgnored(diag::warn_for_range_const_ref_binds_temp_built_from_ref, + ForStmt->getBeginLoc()) && + Diags.isIgnored(diag::warn_for_range_ref_binds_ret_temp, + ForStmt->getBeginLoc()) && + Diags.isIgnored(diag::warn_for_range_copy, ForStmt->getBeginLoc())) return; - } const VarDecl *VD = ForStmt->getLoopVariable(); if (!VD) @@ -2875,10 +2829,10 @@ return; if (VariableType->isReferenceType()) { - DiagnoseForRangeReferenceVariableCopies(SemaRef, VD, + DiagnoseForRangeReferenceVariableCopies(VD, ForStmt->getRangeInit()->getType()); } else if (VariableType.isConstQualified()) { - DiagnoseForRangeConstVariableCopies(SemaRef, VD); + DiagnoseForRangeConstVariableCopies(VD); } } @@ -2899,7 +2853,7 @@ DiagnoseEmptyStmtBody(ForStmt->getRParenLoc(), B, diag::warn_empty_range_based_for_body); - DiagnoseForRangeVariableCopies(*this, ForStmt); + DiagnoseForRangeVariableCopies(ForStmt); return S; } @@ -2939,11 +2893,11 @@ 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); +void Sema::CheckJumpOutOfSEHFinally(SourceLocation Loc, + const Scope &DestScope) { + if (!CurrentSEHFinally.empty() && + DestScope.Contains(*CurrentSEHFinally.back())) { + Diag(Loc, diag::warn_jump_out_of_seh_finally); } } @@ -2954,7 +2908,7 @@ // 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); + CheckJumpOutOfSEHFinally(ContinueLoc, *S); return new (Context) ContinueStmt(ContinueLoc); } @@ -2969,7 +2923,7 @@ if (S->isOpenMPLoopScope()) return StmtError(Diag(BreakLoc, diag::err_omp_loop_cannot_use_stmt) << "break"); - CheckJumpOutOfSEHFinally(*this, BreakLoc, *S); + CheckJumpOutOfSEHFinally(BreakLoc, *S); return new (Context) BreakStmt(BreakLoc); } @@ -3054,29 +3008,11 @@ return true; } -/// Try to perform the initialization of a potentially-movable value, -/// which is the operand to a return or throw statement. -/// -/// This routine implements C++14 [class.copy]p32, which attempts to treat -/// returned lvalues as rvalues in certain cases (to prefer move construction), -/// then falls back to treating them as lvalues if that failed. -/// -/// \param ConvertingConstructorsOnly If true, follow [class.copy]p32 and reject -/// resolutions that find non-constructors, such as derived-to-base conversions -/// or `operator T()&&` member functions. If false, do consider such -/// conversion sequences. -/// -/// \param Res We will fill this in if move-initialization was possible. -/// If move-initialization is not possible, such that we must fall back to -/// treating the operand as an lvalue, we will leave Res in its original -/// invalid state. -static void TryMoveInitialization(Sema& S, - const InitializedEntity &Entity, - const VarDecl *NRVOCandidate, - QualType ResultType, - Expr *&Value, - bool ConvertingConstructorsOnly, - ExprResult &Res) { +void Sema::TryMoveInitialization(const InitializedEntity &Entity, + const VarDecl *NRVOCandidate, + QualType ResultType, Expr *&Value, + bool ConvertingConstructorsOnly, + ExprResult &Res) { ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(), CK_NoOp, Value, VK_XValue); @@ -3085,7 +3021,7 @@ InitializationKind Kind = InitializationKind::CreateCopy( Value->getBeginLoc(), Value->getBeginLoc()); - InitializationSequence Seq(S, Entity, Kind, InitExpr); + InitializationSequence Seq(*this, Entity, Kind, InitExpr); if (!Seq) return; @@ -3108,8 +3044,8 @@ FD->getParamDecl(0)->getType()->getAs(); if (!RRefType) break; - if (!S.Context.hasSameUnqualifiedType(RRefType->getPointeeType(), - NRVOCandidate->getType())) + if (!Context.hasSameUnqualifiedType(RRefType->getPointeeType(), + NRVOCandidate->getType())) break; } else { continue; @@ -3133,12 +3069,12 @@ // Promote "AsRvalue" to the heap, since we now need this // expression node to persist. - Value = ImplicitCastExpr::Create(S.Context, Value->getType(), CK_NoOp, - Value, nullptr, VK_XValue); + Value = ImplicitCastExpr::Create(Context, Value->getType(), CK_NoOp, Value, + nullptr, VK_XValue); // Complete type-checking the initialization of the return type // using the constructor we found. - Res = Seq.Perform(S, Entity, Kind, Value); + Res = Seq.Perform(*this, Entity, Kind, Value); } } @@ -3180,8 +3116,8 @@ } if (NRVOCandidate) { - TryMoveInitialization(*this, Entity, NRVOCandidate, ResultType, Value, - true, Res); + TryMoveInitialization(Entity, NRVOCandidate, ResultType, Value, true, + Res); } if (!Res.isInvalid() && AffectedByCWG1579) { @@ -3225,7 +3161,7 @@ } else { ExprResult FakeRes = ExprError(); Expr *FakeValue = Value; - TryMoveInitialization(*this, Entity, FakeNRVOCandidate, ResultType, + TryMoveInitialization(Entity, FakeNRVOCandidate, ResultType, FakeValue, false, FakeRes); if (!FakeRes.isInvalid()) { bool IsThrow = @@ -3601,7 +3537,7 @@ CurScope->setNoNRVO(); } - CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent()); + CheckJumpOutOfSEHFinally(ReturnLoc, *CurScope->getFnParent()); return R; } @@ -4248,7 +4184,7 @@ SEHTryParent = SEHTryParent->getParent(); if (!SEHTryParent) return StmtError(Diag(Loc, diag::err_ms___leave_not_in___try)); - CheckJumpOutOfSEHFinally(*this, Loc, *SEHTryParent); + CheckJumpOutOfSEHFinally(Loc, *SEHTryParent); return new (Context) SEHLeaveStmt(Loc); } @@ -4301,23 +4237,23 @@ return RD; } -static bool -buildCapturedStmtCaptureList(Sema &S, CapturedRegionScopeInfo *RSI, - SmallVectorImpl &Captures, - SmallVectorImpl &CaptureInits) { +bool Sema::BuildCapturedStmtCaptureList( + CapturedRegionScopeInfo *RSI, + SmallVectorImpl &Captures, + SmallVectorImpl &CaptureInits) { for (const sema::Capture &Cap : RSI->Captures) { if (Cap.isInvalid()) continue; // Form the initializer for the capture. - ExprResult Init = S.BuildCaptureInit(Cap, Cap.getLocation(), - RSI->CapRegionKind == CR_OpenMP); + ExprResult Init = BuildCaptureInit(Cap, Cap.getLocation(), + RSI->CapRegionKind == CR_OpenMP); // FIXME: Bail out now if the capture is not used and the initializer has // no side-effects. // Create a field for this capture. - FieldDecl *Field = S.BuildCaptureField(RSI->TheRecordDecl, Cap); + FieldDecl *Field = BuildCaptureField(RSI->TheRecordDecl, Cap); // Add the capture to our list of captures. if (Cap.isThisCapture()) { @@ -4329,8 +4265,8 @@ } else { assert(Cap.isVariableCapture() && "unknown kind of capture"); - if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) - S.setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel); + if (getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) + setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel); Captures.push_back(CapturedStmt::Capture(Cap.getLocation(), Cap.isReferenceCapture() @@ -4457,7 +4393,7 @@ SmallVector Captures; SmallVector CaptureInits; - if (buildCapturedStmtCaptureList(*this, RSI, Captures, CaptureInits)) + if (BuildCapturedStmtCaptureList(RSI, Captures, CaptureInits)) return StmtError(); CapturedDecl *CD = RSI->TheCapturedDecl;