summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/tools/clang/lib/Sema/SemaStmt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/llvm/tools/clang/lib/Sema/SemaStmt.cpp')
-rw-r--r--gnu/llvm/tools/clang/lib/Sema/SemaStmt.cpp404
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();