diff options
Diffstat (limited to 'gnu/llvm/tools/clang/lib/Sema/SemaStmt.cpp')
| -rw-r--r-- | gnu/llvm/tools/clang/lib/Sema/SemaStmt.cpp | 404 |
1 files changed, 236 insertions, 168 deletions
diff --git a/gnu/llvm/tools/clang/lib/Sema/SemaStmt.cpp b/gnu/llvm/tools/clang/lib/Sema/SemaStmt.cpp index e1b1a47e182..8e8104e581b 100644 --- a/gnu/llvm/tools/clang/lib/Sema/SemaStmt.cpp +++ b/gnu/llvm/tools/clang/lib/Sema/SemaStmt.cpp @@ -37,6 +37,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" + using namespace clang; using namespace sema; @@ -249,10 +250,10 @@ 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()) { - const FunctionDecl *Func = dyn_cast<FunctionDecl>(FD); - if (Func ? Func->hasUnusedResultAttr() - : FD->hasAttr<WarnUnusedResultAttr>()) { - Diag(Loc, diag::warn_unused_result) << R1 << R2; + if (const Attr *A = isa<FunctionDecl>(FD) + ? cast<FunctionDecl>(FD)->getUnusedResultAttr() + : FD->getAttr<WarnUnusedResultAttr>()) { + Diag(Loc, diag::warn_unused_result) << A << R1 << R2; return; } if (ShouldSuppress) @@ -276,8 +277,8 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD) { - if (MD->hasAttr<WarnUnusedResultAttr>()) { - Diag(Loc, diag::warn_unused_result) << R1 << R2; + if (const auto *A = MD->getAttr<WarnUnusedResultAttr>()) { + Diag(Loc, diag::warn_unused_result) << A << R1 << R2; return; } } @@ -488,36 +489,62 @@ StmtResult Sema::ActOnAttributedStmt(SourceLocation AttrLoc, return LS; } +namespace { +class CommaVisitor : public EvaluatedExprVisitor<CommaVisitor> { + typedef EvaluatedExprVisitor<CommaVisitor> Inherited; + Sema &SemaRef; +public: + CommaVisitor(Sema &SemaRef) : Inherited(SemaRef.Context), SemaRef(SemaRef) {} + void VisitBinaryOperator(BinaryOperator *E) { + if (E->getOpcode() == BO_Comma) + SemaRef.DiagnoseCommaOperator(E->getLHS(), E->getExprLoc()); + EvaluatedExprVisitor<CommaVisitor>::VisitBinaryOperator(E); + } +}; +} + StmtResult -Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, +Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt, + ConditionResult Cond, Stmt *thenStmt, SourceLocation ElseLoc, Stmt *elseStmt) { - ExprResult CondResult(CondVal.release()); - - VarDecl *ConditionVar = nullptr; - if (CondVar) { - ConditionVar = cast<VarDecl>(CondVar); - CondResult = CheckConditionVariable(ConditionVar, IfLoc, true); - CondResult = ActOnFinishFullExpr(CondResult.get(), IfLoc); - } - Expr *ConditionExpr = CondResult.getAs<Expr>(); - if (ConditionExpr) { - DiagnoseUnusedExprResult(thenStmt); + if (Cond.isInvalid()) + Cond = ConditionResult( + *this, nullptr, + MakeFullExpr(new (Context) OpaqueValueExpr(SourceLocation(), + Context.BoolTy, VK_RValue), + IfLoc), + false); + + Expr *CondExpr = Cond.get().second; + if (!Diags.isIgnored(diag::warn_comma_operator, + CondExpr->getExprLoc())) + CommaVisitor(*this).Visit(CondExpr); + + if (!elseStmt) + DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), thenStmt, + diag::warn_empty_if_body); + + return BuildIfStmt(IfLoc, IsConstexpr, InitStmt, Cond, thenStmt, ElseLoc, + elseStmt); +} + +StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, + Stmt *InitStmt, ConditionResult Cond, + Stmt *thenStmt, SourceLocation ElseLoc, + Stmt *elseStmt) { + if (Cond.isInvalid()) + return StmtError(); - if (!elseStmt) { - DiagnoseEmptyStmtBody(ConditionExpr->getLocEnd(), thenStmt, - diag::warn_empty_if_body); - } + if (IsConstexpr) + getCurFunction()->setHasBranchProtectedScope(); - DiagnoseUnusedExprResult(elseStmt); - } else { - // Create a dummy Expr for the condition for error recovery - ConditionExpr = new (Context) OpaqueValueExpr(SourceLocation(), - Context.BoolTy, VK_RValue); - } + DiagnoseUnusedExprResult(thenStmt); + DiagnoseUnusedExprResult(elseStmt); - return new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr, - thenStmt, ElseLoc, elseStmt); + return new (Context) + IfStmt(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first, + Cond.get().second, thenStmt, ElseLoc, elseStmt); } namespace { @@ -579,24 +606,7 @@ static QualType GetTypeBeforeIntegralPromotion(Expr *&expr) { return expr->getType(); } -StmtResult -Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, - Decl *CondVar) { - ExprResult CondResult; - - VarDecl *ConditionVar = nullptr; - if (CondVar) { - ConditionVar = cast<VarDecl>(CondVar); - CondResult = CheckConditionVariable(ConditionVar, SourceLocation(), false); - if (CondResult.isInvalid()) - return StmtError(); - - Cond = CondResult.get(); - } - - if (!Cond) - return StmtError(); - +ExprResult Sema::CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond) { class SwitchConvertDiagnoser : public ICEConvertDiagnoser { Expr *Cond; @@ -644,24 +654,24 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, } } SwitchDiagnoser(Cond); - CondResult = + ExprResult CondResult = PerformContextualImplicitConversion(SwitchLoc, Cond, SwitchDiagnoser); - if (CondResult.isInvalid()) return StmtError(); - Cond = CondResult.get(); + if (CondResult.isInvalid()) + return ExprError(); // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. - CondResult = UsualUnaryConversions(Cond); - if (CondResult.isInvalid()) return StmtError(); - Cond = CondResult.get(); + return UsualUnaryConversions(CondResult.get()); +} - CondResult = ActOnFinishFullExpr(Cond, SwitchLoc); - if (CondResult.isInvalid()) +StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, + Stmt *InitStmt, ConditionResult Cond) { + if (Cond.isInvalid()) return StmtError(); - Cond = CondResult.get(); getCurFunction()->setHasBranchIntoScope(); - SwitchStmt *SS = new (Context) SwitchStmt(Context, ConditionVar, Cond); + SwitchStmt *SS = new (Context) + SwitchStmt(Context, InitStmt, Cond.get().first, Cond.get().second); getCurFunction()->SwitchStack.push_back(SS); return SS; } @@ -980,7 +990,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, << SourceRange(CR->getLHS()->getLocStart(), Hi->getLocEnd()); CaseRanges.erase(CaseRanges.begin()+i); - --i, --e; + --i; + --e; continue; } @@ -1221,23 +1232,17 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, } } -StmtResult -Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, - Decl *CondVar, Stmt *Body) { - ExprResult CondResult(Cond.release()); - - VarDecl *ConditionVar = nullptr; - if (CondVar) { - ConditionVar = cast<VarDecl>(CondVar); - CondResult = CheckConditionVariable(ConditionVar, WhileLoc, true); - CondResult = ActOnFinishFullExpr(CondResult.get(), WhileLoc); - if (CondResult.isInvalid()) - return StmtError(); - } - Expr *ConditionExpr = CondResult.get(); - if (!ConditionExpr) +StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond, + Stmt *Body) { + if (Cond.isInvalid()) return StmtError(); - CheckBreakContinueBinding(ConditionExpr); + + auto CondVal = Cond.get(); + CheckBreakContinueBinding(CondVal.second); + + if (CondVal.second && + !Diags.isIgnored(diag::warn_comma_operator, CondVal.second->getExprLoc())) + CommaVisitor(*this).Visit(CondVal.second); DiagnoseUnusedExprResult(Body); @@ -1245,7 +1250,7 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, getCurCompoundScope().setHasEmptyLoopBodies(); return new (Context) - WhileStmt(Context, ConditionVar, ConditionExpr, Body, WhileLoc); + WhileStmt(Context, CondVal.first, CondVal.second, Body, WhileLoc); } StmtResult @@ -1255,7 +1260,7 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, assert(Cond && "ActOnDoStmt(): missing expression"); CheckBreakContinueBinding(Cond); - ExprResult CondResult = CheckBooleanCondition(Cond, DoLoc); + ExprResult CondResult = CheckBooleanCondition(DoLoc, Cond); if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.get(); @@ -1416,6 +1421,18 @@ namespace { FoundDecl = true; } + void VisitPseudoObjectExpr(PseudoObjectExpr *POE) { + // Only need to visit the semantics for POE. + // SyntaticForm doesn't really use the Decal. + for (auto *S : POE->semantics()) { + if (auto *OVE = dyn_cast<OpaqueValueExpr>(S)) + // Look past the OVE into the expression it binds. + Visit(OVE->getSourceExpr()); + else + Visit(S); + } + } + bool FoundDeclInUse() { return FoundDecl; } }; // end class DeclMatcher @@ -1481,6 +1498,10 @@ namespace { // variables Increment and DRE. bool ProcessIterationStmt(Sema &S, Stmt* Statement, bool &Increment, DeclRefExpr *&DRE) { + if (auto Cleanups = dyn_cast<ExprWithCleanups>(Statement)) + if (!Cleanups->cleanupsHaveSideEffects()) + Statement = Cleanups->getSubExpr(); + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(Statement)) { switch (UO->getOpcode()) { default: return false; @@ -1603,11 +1624,13 @@ void Sema::CheckBreakContinueBinding(Expr *E) { } } -StmtResult -Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - Stmt *First, FullExprArg second, Decl *secondVar, - FullExprArg third, - SourceLocation RParenLoc, Stmt *Body) { +StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, + Stmt *First, ConditionResult Second, + FullExprArg third, SourceLocation RParenLoc, + Stmt *Body) { + if (Second.isInvalid()) + return StmtError(); + if (!getLangOpts().CPlusPlus) { if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) { // C99 6.8.5p3: The declaration part of a 'for' statement shall only @@ -1625,21 +1648,18 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, } } - CheckBreakContinueBinding(second.get()); + CheckBreakContinueBinding(Second.get().second); CheckBreakContinueBinding(third.get()); - CheckForLoopConditionalStatement(*this, second.get(), third.get(), Body); + if (!Second.get().first) + CheckForLoopConditionalStatement(*this, Second.get().second, third.get(), + Body); CheckForRedundantIteration(*this, third.get(), Body); - ExprResult SecondResult(second.release()); - VarDecl *ConditionVar = nullptr; - if (secondVar) { - ConditionVar = cast<VarDecl>(secondVar); - SecondResult = CheckConditionVariable(ConditionVar, ForLoc, true); - SecondResult = ActOnFinishFullExpr(SecondResult.get(), ForLoc); - if (SecondResult.isInvalid()) - return StmtError(); - } + if (Second.get().second && + !Diags.isIgnored(diag::warn_comma_operator, + Second.get().second->getExprLoc())) + CommaVisitor(*this).Visit(Second.get().second); Expr *Third = third.release().getAs<Expr>(); @@ -1650,8 +1670,9 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, if (isa<NullStmt>(Body)) getCurCompoundScope().setHasEmptyLoopBodies(); - return new (Context) ForStmt(Context, First, SecondResult.get(), ConditionVar, - Third, Body, ForLoc, LParenLoc, RParenLoc); + return new (Context) + ForStmt(Context, First, Second.get().second, Second.get().first, Third, + Body, ForLoc, LParenLoc, RParenLoc); } /// In an Objective C collection iteration statement: @@ -1992,8 +2013,9 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, } return BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, RangeDecl.get(), - /*BeginEndDecl=*/nullptr, /*Cond=*/nullptr, - /*Inc=*/nullptr, DS, RParenLoc, Kind); + /*BeginStmt=*/nullptr, /*EndStmt=*/nullptr, + /*Cond=*/nullptr, /*Inc=*/nullptr, + DS, RParenLoc, Kind); } /// \brief Create the initialization, compare, and increment steps for @@ -2143,8 +2165,8 @@ struct InvalidateOnErrorScope { /// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement. StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, - SourceLocation ColonLoc, - Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond, + SourceLocation ColonLoc, Stmt *RangeDecl, + Stmt *Begin, Stmt *End, Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, SourceLocation RParenLoc, BuildForRangeKind Kind) { // FIXME: This should not be used during template instantiation. We should @@ -2170,7 +2192,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, InvalidateOnErrorScope Invalidate(*this, LoopVar, LoopVar->getType()->isUndeducedType()); - StmtResult BeginEndDecl = BeginEnd; + StmtResult BeginDeclStmt = Begin; + StmtResult EndDeclStmt = End; ExprResult NotEqExpr = Cond, IncrExpr = Inc; if (RangeVarType->isDependentType()) { @@ -2181,7 +2204,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, // them in properly when we instantiate the loop. if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy)); - } else if (!BeginEndDecl.get()) { + } else if (!BeginDeclStmt.get()) { SourceLocation RangeLoc = RangeVar->getLocation(); const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType(); @@ -2306,20 +2329,21 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, "invalid range expression in for loop"); // C++11 [dcl.spec.auto]p7: BeginType and EndType must be the same. + // C++1z removes this restriction. QualType BeginType = BeginVar->getType(), EndType = EndVar->getType(); if (!Context.hasSameType(BeginType, EndType)) { - Diag(RangeLoc, diag::err_for_range_begin_end_types_differ) - << BeginType << EndType; + Diag(RangeLoc, getLangOpts().CPlusPlus1z + ? diag::warn_for_range_begin_end_types_differ + : diag::ext_for_range_begin_end_types_differ) + << BeginType << EndType; NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end); } - Decl *BeginEndDecls[] = { BeginVar, EndVar }; - // Claim the type doesn't contain auto: we've already done the checking. - DeclGroupPtrTy BeginEndGroup = - BuildDeclaratorGroup(MutableArrayRef<Decl *>(BeginEndDecls, 2), - /*TypeMayContainAuto=*/ false); - BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc); + BeginDeclStmt = + ActOnDeclStmt(ConvertDeclToDeclGroup(BeginVar), ColonLoc, ColonLoc); + EndDeclStmt = + ActOnDeclStmt(ConvertDeclToDeclGroup(EndVar), ColonLoc, ColonLoc); const QualType BeginRefNonRefType = BeginType.getNonReferenceType(); ExprResult BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType, @@ -2335,8 +2359,10 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, // Build and check __begin != __end expression. NotEqExpr = ActOnBinOp(S, ColonLoc, tok::exclaimequal, BeginRef.get(), EndRef.get()); - NotEqExpr = ActOnBooleanCondition(S, ColonLoc, NotEqExpr.get()); - NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get()); + if (!NotEqExpr.isInvalid()) + NotEqExpr = CheckBooleanCondition(ColonLoc, NotEqExpr.get()); + if (!NotEqExpr.isInvalid()) + NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get()); if (NotEqExpr.isInvalid()) { Diag(RangeLoc, diag::note_for_range_invalid_iterator) << RangeLoc << 0 << BeginRangeRef.get()->getType(); @@ -2394,7 +2420,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, return StmtResult(); return new (Context) CXXForRangeStmt( - RangeDS, cast_or_null<DeclStmt>(BeginEndDecl.get()), NotEqExpr.get(), + RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()), + cast_or_null<DeclStmt>(EndDeclStmt.get()), NotEqExpr.get(), IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc, ColonLoc, RParenLoc); } @@ -2426,6 +2453,10 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef, QualType VariableType = VD->getType(); + if (auto Cleanups = dyn_cast<ExprWithCleanups>(InitExpr)) + if (!Cleanups->cleanupsHaveSideEffects()) + InitExpr = Cleanups->getSubExpr(); + const MaterializeTemporaryExpr *MTE = dyn_cast<MaterializeTemporaryExpr>(InitExpr); @@ -2663,16 +2694,16 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { /// \param E The expression being returned from the function or block, or /// being thrown. /// -/// \param AllowFunctionParameter Whether we allow function parameters to -/// be considered NRVO candidates. C++ prohibits this for NRVO itself, but -/// we re-use this logic to determine whether we should try to move as part of -/// a return or throw (which does allow function parameters). +/// \param AllowParamOrMoveConstructible Whether we allow function parameters or +/// id-expressions that could be moved out of the function to be considered NRVO +/// candidates. C++ prohibits these for NRVO itself, but we re-use this logic to +/// determine whether we should try to move as part of a return or throw (which +/// does allow function parameters). /// /// \returns The NRVO candidate variable, if the return statement may use the /// NRVO, or NULL if there is no such candidate. -VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, - Expr *E, - bool AllowFunctionParameter) { +VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, Expr *E, + bool AllowParamOrMoveConstructible) { if (!getLangOpts().CPlusPlus) return nullptr; @@ -2685,13 +2716,13 @@ VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, if (!VD) return nullptr; - if (isCopyElisionCandidate(ReturnType, VD, AllowFunctionParameter)) + if (isCopyElisionCandidate(ReturnType, VD, AllowParamOrMoveConstructible)) return VD; return nullptr; } bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, - bool AllowFunctionParameter) { + bool AllowParamOrMoveConstructible) { QualType VDType = VD->getType(); // - in a return statement in a function with ... // ... a class return type ... @@ -2699,20 +2730,24 @@ bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, if (!ReturnType->isRecordType()) return false; // ... the same cv-unqualified type as the function return type ... - if (!VDType->isDependentType() && + // When considering moving this expression out, allow dissimilar types. + if (!AllowParamOrMoveConstructible && !VDType->isDependentType() && !Context.hasSameUnqualifiedType(ReturnType, VDType)) return false; } // ...object (other than a function or catch-clause parameter)... if (VD->getKind() != Decl::Var && - !(AllowFunctionParameter && VD->getKind() == Decl::ParmVar)) + !(AllowParamOrMoveConstructible && VD->getKind() == Decl::ParmVar)) return false; if (VD->isExceptionVariable()) return false; // ...automatic... if (!VD->hasLocalStorage()) return false; + if (AllowParamOrMoveConstructible) + return true; + // ...non-volatile... if (VD->getType().isVolatileQualified()) return false; @@ -2731,7 +2766,7 @@ bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, /// \brief Perform the initialization of a potentially-movable value, which /// is the result of return value. /// -/// This routine implements C++0x [class.copy]p33, which attempts to treat +/// 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. ExprResult @@ -2740,52 +2775,59 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, QualType ResultType, Expr *Value, bool AllowNRVO) { - // C++0x [class.copy]p33: - // When the criteria for elision of a copy operation are met or would - // be met save for the fact that the source object is a function - // parameter, and the object to be copied is designated by an lvalue, - // overload resolution to select the constructor for the copy is first - // performed as if the object were designated by an rvalue. + // C++14 [class.copy]p32: + // When the criteria for elision of a copy/move operation are met, but not for + // an exception-declaration, and the object to be copied is designated by an + // lvalue, or when the expression in a return statement is a (possibly + // parenthesized) id-expression that names an object with automatic storage + // duration declared in the body or parameter-declaration-clause of the + // innermost enclosing function or lambda-expression, overload resolution to + // select the constructor for the copy is first performed as if the object + // were designated by an rvalue. ExprResult Res = ExprError(); - if (AllowNRVO && - (NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true))) { - ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, - Value->getType(), CK_NoOp, Value, VK_XValue); + + if (AllowNRVO && !NRVOCandidate) + NRVOCandidate = getCopyElisionCandidate(ResultType, Value, true); + + if (AllowNRVO && NRVOCandidate) { + ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(), + CK_NoOp, Value, VK_XValue); Expr *InitExpr = &AsRvalue; - InitializationKind Kind - = InitializationKind::CreateCopy(Value->getLocStart(), - Value->getLocStart()); - InitializationSequence Seq(*this, Entity, Kind, InitExpr); - // [...] If overload resolution fails, or if the type of the first - // parameter of the selected constructor is not an rvalue reference - // to the object's type (possibly cv-qualified), overload resolution - // is performed again, considering the object as an lvalue. + InitializationKind Kind = InitializationKind::CreateCopy( + Value->getLocStart(), Value->getLocStart()); + + InitializationSequence Seq(*this, Entity, Kind, InitExpr); if (Seq) { - for (InitializationSequence::step_iterator Step = Seq.step_begin(), - StepEnd = Seq.step_end(); - Step != StepEnd; ++Step) { - if (Step->Kind != InitializationSequence::SK_ConstructorInitialization) + for (const InitializationSequence::Step &Step : Seq.steps()) { + if (!(Step.Kind == + InitializationSequence::SK_ConstructorInitialization || + (Step.Kind == InitializationSequence::SK_UserConversion && + isa<CXXConstructorDecl>(Step.Function.Function)))) continue; - CXXConstructorDecl *Constructor - = cast<CXXConstructorDecl>(Step->Function.Function); + CXXConstructorDecl *Constructor = + cast<CXXConstructorDecl>(Step.Function.Function); const RValueReferenceType *RRefType = Constructor->getParamDecl(0)->getType() ->getAs<RValueReferenceType>(); - // If we don't meet the criteria, break out now. + // [...] If the first overload resolution fails or was not performed, or + // if the type of the first parameter of the selected constructor is not + // an rvalue reference to the object’s type (possibly cv-qualified), + // overload resolution is performed again, considering the object as an + // lvalue. if (!RRefType || !Context.hasSameUnqualifiedType(RRefType->getPointeeType(), - Context.getTypeDeclType(Constructor->getParent()))) + NRVOCandidate->getType())) break; // Promote "AsRvalue" to the heap, since we now need this // expression node to persist. - Value = ImplicitCastExpr::Create(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. @@ -2821,8 +2863,21 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction()); QualType FnRetType = CurCap->ReturnType; LambdaScopeInfo *CurLambda = dyn_cast<LambdaScopeInfo>(CurCap); + bool HasDeducedReturnType = + CurLambda && hasDeducedReturnType(CurLambda->CallOperator); + + if (ExprEvalContexts.back().Context == DiscardedStatement && + (HasDeducedReturnType || CurCap->HasImplicitReturnType)) { + if (RetValExp) { + ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc); + if (ER.isInvalid()) + return StmtError(); + RetValExp = ER.get(); + } + return new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr); + } - if (CurLambda && hasDeducedReturnType(CurLambda->CallOperator)) { + if (HasDeducedReturnType) { // In C++1y, the return type may involve 'auto'. // FIXME: Blocks might have a return type of 'auto' explicitly specified. FunctionDecl *FD = CurLambda->CallOperator; @@ -3066,22 +3121,28 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, // has multiple return statements, the return type is deduced for each return // statement. [...] if the type deduced is not the same in each deduction, // the program is ill-formed. - if (AT->isDeduced() && !FD->isInvalidDecl()) { + QualType DeducedT = AT->getDeducedType(); + if (!DeducedT.isNull() && !FD->isInvalidDecl()) { AutoType *NewAT = Deduced->getContainedAutoType(); + // It is possible that NewAT->getDeducedType() is null. When that happens, + // we should not crash, instead we ignore this deduction. + if (NewAT->getDeducedType().isNull()) + return false; + CanQualType OldDeducedType = Context.getCanonicalFunctionResultType( - AT->getDeducedType()); + DeducedT); CanQualType NewDeducedType = Context.getCanonicalFunctionResultType( NewAT->getDeducedType()); if (!FD->isDependentContext() && OldDeducedType != NewDeducedType) { const LambdaScopeInfo *LambdaSI = getCurLambda(); if (LambdaSI && LambdaSI->HasImplicitReturnType) { Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible) - << NewAT->getDeducedType() << AT->getDeducedType() + << NewAT->getDeducedType() << DeducedT << true /*IsLambda*/; } else { Diag(ReturnLoc, diag::err_auto_fn_different_deductions) << (AT->isDecltypeAuto() ? 1 : 0) - << NewAT->getDeducedType() << AT->getDeducedType(); + << NewAT->getDeducedType() << DeducedT; } return true; } @@ -3097,9 +3158,8 @@ StmtResult Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, Scope *CurScope) { StmtResult R = BuildReturnStmt(ReturnLoc, RetValExp); - if (R.isInvalid()) { + if (R.isInvalid() || ExprEvalContexts.back().Context == DiscardedStatement) return R; - } if (VarDecl *VD = const_cast<VarDecl*>(cast<ReturnStmt>(R.get())->getNRVOCandidate())) { @@ -3148,6 +3208,19 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } else // If we don't have a function/method context, bail. return StmtError(); + // C++1z: discarded return statements are not considered when deducing a + // return type. + if (ExprEvalContexts.back().Context == DiscardedStatement && + FnRetType->getContainedAutoType()) { + if (RetValExp) { + ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc); + if (ER.isInvalid()) + return StmtError(); + RetValExp = ER.get(); + } + return new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr); + } + // FIXME: Add a flag to the ScopeInfo to indicate whether we're performing // deduction. if (getLangOpts().CPlusPlus14) { @@ -3525,11 +3598,6 @@ template <> struct DenseMapInfo<CatchHandlerType> { return LHS == RHS; } }; - -// It's OK to treat CatchHandlerType as a POD type. -template <> struct isPodLike<CatchHandlerType> { - static const bool value = true; -}; } namespace { @@ -3554,7 +3622,7 @@ public: bool operator()(const CXXBaseSpecifier *S, CXXBasePath &) { if (S->getAccessSpecifier() == AccessSpecifier::AS_public) { CatchHandlerType Check(S->getType(), CheckAgainstPointer); - auto M = TypesToCheck; + const auto &M = TypesToCheck; auto I = M.find(Check); if (I != M.end()) { FoundHandler = I->second; @@ -3916,9 +3984,9 @@ StmtResult Sema::ActOnCapturedRegionEnd(Stmt *S) { CapturedDecl *CD = RSI->TheCapturedDecl; RecordDecl *RD = RSI->TheRecordDecl; - CapturedStmt *Res = CapturedStmt::Create(getASTContext(), S, - RSI->CapRegionKind, Captures, - CaptureInits, CD, RD); + CapturedStmt *Res = CapturedStmt::Create( + getASTContext(), S, static_cast<CapturedRegionKind>(RSI->CapRegionKind), + Captures, CaptureInits, CD, RD); CD->setBody(Res->getCapturedStmt()); RD->completeDefinition(); |
