diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp | 1273 |
1 files changed, 810 insertions, 463 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp b/contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp index b24a8ab110b2..9e7c8c7e4e8c 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp @@ -10,17 +10,16 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/Ownership.h" -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTLambda.h" -#include "clang/AST/CharUnits.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/IgnoreExpr.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" @@ -30,14 +29,17 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Ownership.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.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" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" using namespace clang; using namespace sema; @@ -215,9 +217,9 @@ static bool DiagnoseNoDiscard(Sema &S, const WarnUnusedResultAttr *A, return S.Diag(Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2; } -void Sema::DiagnoseUnusedExprResult(const Stmt *S) { +void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) - return DiagnoseUnusedExprResult(Label->getSubStmt()); + return DiagnoseUnusedExprResult(Label->getSubStmt(), DiagID); const Expr *E = dyn_cast_or_null<Expr>(S); if (!E) @@ -263,7 +265,6 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { // Okay, we have an unused result. Depending on what the base expression is, // we might want to make a more specific diagnostic. Check for one of these // cases now. - unsigned DiagID = diag::warn_unused_expr; if (const FullExpr *Temps = dyn_cast<FullExpr>(E)) E = Temps->getSubExpr(); if (const CXXBindTemporaryExpr *TempExpr = dyn_cast<CXXBindTemporaryExpr>(E)) @@ -338,10 +339,10 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (LangOpts.OpenMP && isa<CallExpr>(Source) && POE->getNumSemanticExprs() == 1 && isa<CallExpr>(POE->getSemanticExpr(0))) - return DiagnoseUnusedExprResult(POE->getSemanticExpr(0)); + return DiagnoseUnusedExprResult(POE->getSemanticExpr(0), DiagID); if (isa<ObjCSubscriptRefExpr>(Source)) DiagID = diag::warn_unused_container_subscript_expr; - else + else if (isa<ObjCPropertyRefExpr>(Source)) DiagID = diag::warn_unused_property_expr; } else if (const CXXFunctionalCastExpr *FC = dyn_cast<CXXFunctionalCastExpr>(E)) { @@ -378,7 +379,12 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { return; } - DiagRuntimeBehavior(Loc, nullptr, PDiag(DiagID) << R1 << R2); + // Do not diagnose use of a comma operator in a SFINAE context because the + // type of the left operand could be used for SFINAE, so technically it is + // *used*. + if (DiagID != diag::warn_unused_comma_left_operand || !isSFINAEContext()) + DiagIfReachable(Loc, S ? llvm::ArrayRef(S) : std::nullopt, + PDiag(DiagID) << R1 << R2); } void Sema::ActOnStartOfCompoundStmt(bool IsStmtExpr) { @@ -405,9 +411,13 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, ArrayRef<Stmt *> Elts, bool isStmtExpr) { const unsigned NumElts = Elts.size(); - // If we're in C89 mode, check that we don't have any decls after stmts. If - // so, emit an extension diagnostic. - if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) { + // If we're in C mode, check that we don't have any decls after stmts. If + // so, emit an extension diagnostic in C89 and potentially a warning in later + // versions. + const unsigned MixedDeclsCodeID = getLangOpts().C99 + ? diag::warn_mixed_decls_code + : diag::ext_mixed_decls_code; + if (!getLangOpts().CPlusPlus && !Diags.isIgnored(MixedDeclsCodeID, L)) { // Note that __extension__ can be around a decl. unsigned i = 0; // Skip over all declarations. @@ -420,7 +430,7 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, if (i != NumElts) { Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin(); - Diag(D->getLocation(), diag::ext_mixed_decls_code); + Diag(D->getLocation(), MixedDeclsCodeID); } } @@ -433,7 +443,16 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, DiagnoseEmptyLoopBody(Elts[i], Elts[i + 1]); } - return CompoundStmt::Create(Context, Elts, L, R); + // Calculate difference between FP options in this compound statement and in + // the enclosing one. If this is a function body, take the difference against + // default options. In this case the difference will indicate options that are + // changed upon entry to the statement. + FPOptions FPO = (getCurFunction()->CompoundScopes.size() == 1) + ? FPOptions(getLangOpts()) + : getCurCompoundScope().InitialFPFeatures; + FPOptionsOverride FPDiff = getCurFPFeatures().getChangesFrom(FPO); + + return CompoundStmt::Create(Context, Elts, FPDiff, L, R); } ExprResult @@ -541,6 +560,12 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, return SubStmt; } + ReservedIdentifierStatus Status = TheDecl->isReserved(getLangOpts()); + if (isReservedInAllContexts(Status) && + !Context.getSourceManager().isInSystemHeader(IdentLoc)) + Diag(IdentLoc, diag::warn_reserved_extern_symbol) + << TheDecl << static_cast<int>(Status); + // Otherwise, things are good. Fill in the declaration and return it. LabelStmt *LS = new (Context) LabelStmt(IdentLoc, TheDecl, SubStmt); TheDecl->setStmt(LS); @@ -555,12 +580,292 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, return LS; } -StmtResult Sema::ActOnAttributedStmt(SourceLocation AttrLoc, - ArrayRef<const Attr*> Attrs, +StmtResult Sema::BuildAttributedStmt(SourceLocation AttrsLoc, + ArrayRef<const Attr *> Attrs, Stmt *SubStmt) { - // Fill in the declaration and return it. - AttributedStmt *LS = AttributedStmt::Create(Context, AttrLoc, Attrs, SubStmt); - return LS; + // FIXME: this code should move when a planned refactoring around statement + // attributes lands. + for (const auto *A : Attrs) { + if (A->getKind() == attr::MustTail) { + if (!checkAndRewriteMustTailAttr(SubStmt, *A)) { + return SubStmt; + } + setFunctionHasMustTail(); + } + } + + return AttributedStmt::Create(Context, AttrsLoc, Attrs, SubStmt); +} + +StmtResult Sema::ActOnAttributedStmt(const ParsedAttributes &Attrs, + Stmt *SubStmt) { + SmallVector<const Attr *, 1> SemanticAttrs; + ProcessStmtAttributes(SubStmt, Attrs, SemanticAttrs); + if (!SemanticAttrs.empty()) + return BuildAttributedStmt(Attrs.Range.getBegin(), SemanticAttrs, SubStmt); + // If none of the attributes applied, that's fine, we can recover by + // returning the substatement directly instead of making an AttributedStmt + // with no attributes on it. + return SubStmt; +} + +bool Sema::checkAndRewriteMustTailAttr(Stmt *St, const Attr &MTA) { + ReturnStmt *R = cast<ReturnStmt>(St); + Expr *E = R->getRetValue(); + + if (CurContext->isDependentContext() || (E && E->isInstantiationDependent())) + // We have to suspend our check until template instantiation time. + return true; + + if (!checkMustTailAttr(St, MTA)) + return false; + + // FIXME: Replace Expr::IgnoreImplicitAsWritten() with this function. + // Currently it does not skip implicit constructors in an initialization + // context. + auto IgnoreImplicitAsWritten = [](Expr *E) -> Expr * { + return IgnoreExprNodes(E, IgnoreImplicitAsWrittenSingleStep, + IgnoreElidableImplicitConstructorSingleStep); + }; + + // Now that we have verified that 'musttail' is valid here, rewrite the + // return value to remove all implicit nodes, but retain parentheses. + R->setRetValue(IgnoreImplicitAsWritten(E)); + return true; +} + +bool Sema::checkMustTailAttr(const Stmt *St, const Attr &MTA) { + assert(!CurContext->isDependentContext() && + "musttail cannot be checked from a dependent context"); + + // FIXME: Add Expr::IgnoreParenImplicitAsWritten() with this definition. + auto IgnoreParenImplicitAsWritten = [](const Expr *E) -> const Expr * { + return IgnoreExprNodes(const_cast<Expr *>(E), IgnoreParensSingleStep, + IgnoreImplicitAsWrittenSingleStep, + IgnoreElidableImplicitConstructorSingleStep); + }; + + const Expr *E = cast<ReturnStmt>(St)->getRetValue(); + const auto *CE = dyn_cast_or_null<CallExpr>(IgnoreParenImplicitAsWritten(E)); + + if (!CE) { + Diag(St->getBeginLoc(), diag::err_musttail_needs_call) << &MTA; + return false; + } + + if (const auto *EWC = dyn_cast<ExprWithCleanups>(E)) { + if (EWC->cleanupsHaveSideEffects()) { + Diag(St->getBeginLoc(), diag::err_musttail_needs_trivial_args) << &MTA; + return false; + } + } + + // We need to determine the full function type (including "this" type, if any) + // for both caller and callee. + struct FuncType { + enum { + ft_non_member, + ft_static_member, + ft_non_static_member, + ft_pointer_to_member, + } MemberType = ft_non_member; + + QualType This; + const FunctionProtoType *Func; + const CXXMethodDecl *Method = nullptr; + } CallerType, CalleeType; + + auto GetMethodType = [this, St, MTA](const CXXMethodDecl *CMD, FuncType &Type, + bool IsCallee) -> bool { + if (isa<CXXConstructorDecl, CXXDestructorDecl>(CMD)) { + Diag(St->getBeginLoc(), diag::err_musttail_structors_forbidden) + << IsCallee << isa<CXXDestructorDecl>(CMD); + if (IsCallee) + Diag(CMD->getBeginLoc(), diag::note_musttail_structors_forbidden) + << isa<CXXDestructorDecl>(CMD); + Diag(MTA.getLocation(), diag::note_tail_call_required) << &MTA; + return false; + } + if (CMD->isStatic()) + Type.MemberType = FuncType::ft_static_member; + else { + Type.This = CMD->getFunctionObjectParameterType(); + Type.MemberType = FuncType::ft_non_static_member; + } + Type.Func = CMD->getType()->castAs<FunctionProtoType>(); + return true; + }; + + const auto *CallerDecl = dyn_cast<FunctionDecl>(CurContext); + + // Find caller function signature. + if (!CallerDecl) { + int ContextType; + if (isa<BlockDecl>(CurContext)) + ContextType = 0; + else if (isa<ObjCMethodDecl>(CurContext)) + ContextType = 1; + else + ContextType = 2; + Diag(St->getBeginLoc(), diag::err_musttail_forbidden_from_this_context) + << &MTA << ContextType; + return false; + } else if (const auto *CMD = dyn_cast<CXXMethodDecl>(CurContext)) { + // Caller is a class/struct method. + if (!GetMethodType(CMD, CallerType, false)) + return false; + } else { + // Caller is a non-method function. + CallerType.Func = CallerDecl->getType()->getAs<FunctionProtoType>(); + } + + const Expr *CalleeExpr = CE->getCallee()->IgnoreParens(); + const auto *CalleeBinOp = dyn_cast<BinaryOperator>(CalleeExpr); + SourceLocation CalleeLoc = CE->getCalleeDecl() + ? CE->getCalleeDecl()->getBeginLoc() + : St->getBeginLoc(); + + // Find callee function signature. + if (const CXXMethodDecl *CMD = + dyn_cast_or_null<CXXMethodDecl>(CE->getCalleeDecl())) { + // Call is: obj.method(), obj->method(), functor(), etc. + if (!GetMethodType(CMD, CalleeType, true)) + return false; + } else if (CalleeBinOp && CalleeBinOp->isPtrMemOp()) { + // Call is: obj->*method_ptr or obj.*method_ptr + const auto *MPT = + CalleeBinOp->getRHS()->getType()->castAs<MemberPointerType>(); + CalleeType.This = QualType(MPT->getClass(), 0); + CalleeType.Func = MPT->getPointeeType()->castAs<FunctionProtoType>(); + CalleeType.MemberType = FuncType::ft_pointer_to_member; + } else if (isa<CXXPseudoDestructorExpr>(CalleeExpr)) { + Diag(St->getBeginLoc(), diag::err_musttail_structors_forbidden) + << /* IsCallee = */ 1 << /* IsDestructor = */ 1; + Diag(MTA.getLocation(), diag::note_tail_call_required) << &MTA; + return false; + } else { + // Non-method function. + CalleeType.Func = + CalleeExpr->getType()->getPointeeType()->getAs<FunctionProtoType>(); + } + + // Both caller and callee must have a prototype (no K&R declarations). + if (!CalleeType.Func || !CallerType.Func) { + Diag(St->getBeginLoc(), diag::err_musttail_needs_prototype) << &MTA; + if (!CalleeType.Func && CE->getDirectCallee()) { + Diag(CE->getDirectCallee()->getBeginLoc(), + diag::note_musttail_fix_non_prototype); + } + if (!CallerType.Func) + Diag(CallerDecl->getBeginLoc(), diag::note_musttail_fix_non_prototype); + return false; + } + + // Caller and callee must have matching calling conventions. + // + // Some calling conventions are physically capable of supporting tail calls + // even if the function types don't perfectly match. LLVM is currently too + // strict to allow this, but if LLVM added support for this in the future, we + // could exit early here and skip the remaining checks if the functions are + // using such a calling convention. + if (CallerType.Func->getCallConv() != CalleeType.Func->getCallConv()) { + if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) + Diag(St->getBeginLoc(), diag::err_musttail_callconv_mismatch) + << true << ND->getDeclName(); + else + Diag(St->getBeginLoc(), diag::err_musttail_callconv_mismatch) << false; + Diag(CalleeLoc, diag::note_musttail_callconv_mismatch) + << FunctionType::getNameForCallConv(CallerType.Func->getCallConv()) + << FunctionType::getNameForCallConv(CalleeType.Func->getCallConv()); + Diag(MTA.getLocation(), diag::note_tail_call_required) << &MTA; + return false; + } + + if (CalleeType.Func->isVariadic() || CallerType.Func->isVariadic()) { + Diag(St->getBeginLoc(), diag::err_musttail_no_variadic) << &MTA; + return false; + } + + const auto *CalleeDecl = CE->getCalleeDecl(); + if (CalleeDecl && CalleeDecl->hasAttr<CXX11NoReturnAttr>()) { + Diag(St->getBeginLoc(), diag::err_musttail_no_return) << &MTA; + return false; + } + + // Caller and callee must match in whether they have a "this" parameter. + if (CallerType.This.isNull() != CalleeType.This.isNull()) { + if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) { + Diag(St->getBeginLoc(), diag::err_musttail_member_mismatch) + << CallerType.MemberType << CalleeType.MemberType << true + << ND->getDeclName(); + Diag(CalleeLoc, diag::note_musttail_callee_defined_here) + << ND->getDeclName(); + } else + Diag(St->getBeginLoc(), diag::err_musttail_member_mismatch) + << CallerType.MemberType << CalleeType.MemberType << false; + Diag(MTA.getLocation(), diag::note_tail_call_required) << &MTA; + return false; + } + + auto CheckTypesMatch = [this](FuncType CallerType, FuncType CalleeType, + PartialDiagnostic &PD) -> bool { + enum { + ft_different_class, + ft_parameter_arity, + ft_parameter_mismatch, + ft_return_type, + }; + + auto DoTypesMatch = [this, &PD](QualType A, QualType B, + unsigned Select) -> bool { + if (!Context.hasSimilarType(A, B)) { + PD << Select << A.getUnqualifiedType() << B.getUnqualifiedType(); + return false; + } + return true; + }; + + if (!CallerType.This.isNull() && + !DoTypesMatch(CallerType.This, CalleeType.This, ft_different_class)) + return false; + + if (!DoTypesMatch(CallerType.Func->getReturnType(), + CalleeType.Func->getReturnType(), ft_return_type)) + return false; + + if (CallerType.Func->getNumParams() != CalleeType.Func->getNumParams()) { + PD << ft_parameter_arity << CallerType.Func->getNumParams() + << CalleeType.Func->getNumParams(); + return false; + } + + ArrayRef<QualType> CalleeParams = CalleeType.Func->getParamTypes(); + ArrayRef<QualType> CallerParams = CallerType.Func->getParamTypes(); + size_t N = CallerType.Func->getNumParams(); + for (size_t I = 0; I < N; I++) { + if (!DoTypesMatch(CalleeParams[I], CallerParams[I], + ft_parameter_mismatch)) { + PD << static_cast<int>(I) + 1; + return false; + } + } + + return true; + }; + + PartialDiagnostic PD = PDiag(diag::note_musttail_mismatch); + if (!CheckTypesMatch(CallerType, CalleeType, PD)) { + if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) + Diag(St->getBeginLoc(), diag::err_musttail_mismatch) + << true << ND->getDeclName(); + else + Diag(St->getBeginLoc(), diag::err_musttail_mismatch) << false; + Diag(CalleeLoc, PD); + Diag(MTA.getLocation(), diag::note_tail_call_required) << &MTA; + return false; + } + + return true; } namespace { @@ -577,38 +882,44 @@ public: }; } -StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, +StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, + IfStatementKind StatementKind, SourceLocation LParenLoc, Stmt *InitStmt, ConditionResult Cond, SourceLocation RParenLoc, Stmt *thenStmt, SourceLocation ElseLoc, Stmt *elseStmt) { if (Cond.isInvalid()) - Cond = ConditionResult( - *this, nullptr, - MakeFullExpr(new (Context) OpaqueValueExpr(SourceLocation(), - Context.BoolTy, VK_RValue), - IfLoc), - false); + return StmtError(); + + bool ConstevalOrNegatedConsteval = + StatementKind == IfStatementKind::ConstevalNonNegated || + StatementKind == IfStatementKind::ConstevalNegated; Expr *CondExpr = Cond.get().second; + assert((CondExpr || ConstevalOrNegatedConsteval) && + "If statement: missing condition"); // Only call the CommaVisitor when not C89 due to differences in scope flags. - if ((getLangOpts().C99 || getLangOpts().CPlusPlus) && + if (CondExpr && (getLangOpts().C99 || getLangOpts().CPlusPlus) && !Diags.isIgnored(diag::warn_comma_operator, CondExpr->getExprLoc())) CommaVisitor(*this).Visit(CondExpr); - if (!elseStmt) - DiagnoseEmptyStmtBody(CondExpr->getEndLoc(), thenStmt, - diag::warn_empty_if_body); + if (!ConstevalOrNegatedConsteval && !elseStmt) + DiagnoseEmptyStmtBody(RParenLoc, thenStmt, diag::warn_empty_if_body); - if (IsConstexpr) { + if (ConstevalOrNegatedConsteval || + StatementKind == IfStatementKind::Constexpr) { auto DiagnoseLikelihood = [&](const Stmt *S) { if (const Attr *A = Stmt::getLikelihoodAttr(S)) { Diags.Report(A->getLocation(), - diag::warn_attribute_has_no_effect_on_if_constexpr) - << A << A->getRange(); + diag::warn_attribute_has_no_effect_on_compile_time_if) + << A << ConstevalOrNegatedConsteval << A->getRange(); Diags.Report(IfLoc, - diag::note_attribute_has_no_effect_on_if_constexpr_here) - << SourceRange(IfLoc, LParenLoc.getLocWithOffset(-1)); + diag::note_attribute_has_no_effect_on_compile_time_if_here) + << ConstevalOrNegatedConsteval + << SourceRange(IfLoc, (ConstevalOrNegatedConsteval + ? thenStmt->getBeginLoc() + : LParenLoc) + .getLocWithOffset(-1)); } }; DiagnoseLikelihood(thenStmt); @@ -627,11 +938,25 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, } } - return BuildIfStmt(IfLoc, IsConstexpr, LParenLoc, InitStmt, Cond, RParenLoc, + if (ConstevalOrNegatedConsteval) { + bool Immediate = ExprEvalContexts.back().Context == + ExpressionEvaluationContext::ImmediateFunctionContext; + if (CurContext->isFunctionOrMethod()) { + const auto *FD = + dyn_cast<FunctionDecl>(Decl::castFromDeclContext(CurContext)); + if (FD && FD->isImmediateFunction()) + Immediate = true; + } + if (isUnevaluatedContext() || Immediate) + Diags.Report(IfLoc, diag::warn_consteval_if_always_true) << Immediate; + } + + return BuildIfStmt(IfLoc, StatementKind, LParenLoc, InitStmt, Cond, RParenLoc, thenStmt, ElseLoc, elseStmt); } -StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, +StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, + IfStatementKind StatementKind, SourceLocation LParenLoc, Stmt *InitStmt, ConditionResult Cond, SourceLocation RParenLoc, Stmt *thenStmt, SourceLocation ElseLoc, @@ -639,12 +964,13 @@ StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, if (Cond.isInvalid()) return StmtError(); - if (IsConstexpr || isa<ObjCAvailabilityCheckExpr>(Cond.get().second)) + if (StatementKind != IfStatementKind::Ordinary || + isa<ObjCAvailabilityCheckExpr>(Cond.get().second)) setFunctionHasBranchProtectedScope(); - return IfStmt::Create(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first, - Cond.get().second, LParenLoc, RParenLoc, thenStmt, - ElseLoc, elseStmt); + return IfStmt::Create(Context, IfLoc, StatementKind, InitStmt, + Cond.get().first, Cond.get().second, LParenLoc, + RParenLoc, thenStmt, ElseLoc, elseStmt); } namespace { @@ -825,8 +1151,8 @@ static void checkCaseValue(Sema &S, SourceLocation Loc, const llvm::APSInt &Val, // 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); + S.Diag(Loc, diag::warn_case_value_overflow) << toString(Val, 10) + << toString(ConvVal, 10); } } @@ -951,6 +1277,9 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, bool CaseListIsErroneous = false; + // FIXME: We'd better diagnose missing or duplicate default labels even + // in the dependent case. Because default labels themselves are never + // dependent. for (SwitchCase *SC = SS->getSwitchCaseList(); SC && !HasDependentValue; SC = SC->getNextSwitchCase()) { @@ -1021,6 +1350,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, assert(!HasConstantCond || (ConstantCondValue.getBitWidth() == CondWidth && ConstantCondValue.isSigned() == CondIsSigned)); + Diag(SwitchLoc, diag::warn_switch_default); } bool ShouldCheckConstantCond = HasConstantCond; @@ -1051,12 +1381,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, if (PrevString == CurrString) Diag(CaseVals[i].second->getLHS()->getBeginLoc(), diag::err_duplicate_case) - << (PrevString.empty() ? StringRef(CaseValStr) : PrevString); + << (PrevString.empty() ? CaseValStr.str() : PrevString); else Diag(CaseVals[i].second->getLHS()->getBeginLoc(), diag::err_duplicate_case_differing_expr) - << (PrevString.empty() ? StringRef(CaseValStr) : PrevString) - << (CurrString.empty() ? StringRef(CaseValStr) : CurrString) + << (PrevString.empty() ? CaseValStr.str() : PrevString) + << (CurrString.empty() ? CaseValStr.str() : CurrString) << CaseValStr; Diag(CaseVals[i - 1].second->getLHS()->getBeginLoc(), @@ -1151,7 +1481,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, if (OverlapStmt) { // If we have a duplicate, report it. Diag(CR->getLHS()->getBeginLoc(), diag::err_duplicate_case) - << OverlapVal.toString(10); + << toString(OverlapVal, 10); Diag(OverlapStmt->getLHS()->getBeginLoc(), diag::note_duplicate_case_prev); // FIXME: We really want to remove the bogus case stmt from the @@ -1167,7 +1497,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // TODO: it would be nice if we printed enums as enums, chars as // chars, etc. Diag(CondExpr->getExprLoc(), diag::warn_missing_case_for_condition) - << ConstantCondValue.toString(10) + << toString(ConstantCondValue, 10) << CondExpr->getSourceRange(); } @@ -1180,7 +1510,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // If switch has default case, then ignore it. if (!CaseListIsErroneous && !CaseListIsIncomplete && !HasConstantCond && - ET && ET->getDecl()->isCompleteDefinition()) { + ET && ET->getDecl()->isCompleteDefinition() && + !ET->getDecl()->enumerators().empty()) { const EnumDecl *ED = ET->getDecl(); EnumValsTy EnumVals; @@ -1281,7 +1612,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, auto DB = Diag(CondExpr->getExprLoc(), TheDefaultStmt ? diag::warn_def_missing_case : diag::warn_missing_case) - << (int)UnhandledNames.size(); + << CondExpr->getSourceRange() << (int)UnhandledNames.size(); for (size_t I = 0, E = std::min(UnhandledNames.size(), (size_t)3); I != E; ++I) @@ -1409,9 +1740,7 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, namespace { // Use SetVector since the diagnostic cares about the ordering of the Decl's. - using DeclSetVector = - llvm::SetVector<VarDecl *, llvm::SmallVector<VarDecl *, 8>, - llvm::SmallPtrSet<VarDecl *, 8>>; + using DeclSetVector = llvm::SmallSetVector<VarDecl *, 8>; // This visitor will traverse a conditional statement and store all // the evaluated decls into a vector. Simple is set to true if none @@ -1989,11 +2318,14 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, // If the type contained 'auto', deduce the 'auto' to 'id'. if (FirstType->getContainedAutoType()) { - OpaqueValueExpr OpaqueId(D->getLocation(), Context.getObjCIdType(), - VK_RValue); + SourceLocation Loc = D->getLocation(); + OpaqueValueExpr OpaqueId(Loc, Context.getObjCIdType(), VK_PRValue); Expr *DeducedInit = &OpaqueId; - if (DeduceAutoType(D->getTypeSourceInfo(), DeducedInit, FirstType) == - DAR_Failed) + TemplateDeductionInfo Info(Loc); + FirstType = QualType(); + TemplateDeductionResult Result = DeduceAutoType( + D->getTypeSourceInfo()->getTypeLoc(), DeducedInit, FirstType, Info); + if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) DiagnoseAutoDeductionFailure(D, DeducedInit); if (FirstType.isNull()) { D->setInvalidDecl(); @@ -2057,10 +2389,16 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, // Deduce the type for the iterator variable now rather than leaving it to // AddInitializerToDecl, so we can produce a more suitable diagnostic. QualType InitType; - if ((!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) || - SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitType) == - Sema::DAR_Failed) + if (!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) { SemaRef.Diag(Loc, DiagID) << Init->getType(); + } else { + TemplateDeductionInfo Info(Init->getExprLoc()); + Sema::TemplateDeductionResult Result = SemaRef.DeduceAutoType( + Decl->getTypeSourceInfo()->getTypeLoc(), Init, InitType, Info); + if (Result != Sema::TDK_Success && Result != Sema::TDK_AlreadyDiagnosed) + SemaRef.Diag(Loc, DiagID) << Init->getType(); + } + if (InitType.isNull()) { Decl->setInvalidDecl(); return true; @@ -2156,6 +2494,7 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, Stmt *First, SourceLocation ColonLoc, Expr *Range, SourceLocation RParenLoc, BuildForRangeKind Kind) { + // FIXME: recover in order to allow the body to be parsed. if (!First) return StmtError(); @@ -2340,7 +2679,7 @@ BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange, SemaRef.PDiag(diag::err_for_range_invalid) << BeginRange->getType() << BEFFound), SemaRef, OCD_AllCandidates, BeginRange); - LLVM_FALLTHROUGH; + [[fallthrough]]; case Sema::FRS_DiagnosticIssued: for (NamedDecl *D : OldFound) { @@ -2447,7 +2786,7 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar)) for (auto *Binding : DD->bindings()) Binding->setType(Context.DependentTy); - LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy)); + LoopVar->setType(SubstAutoTypeDependent(LoopVar->getType())); } } else if (!BeginDeclStmt.get()) { SourceLocation RangeLoc = RangeVar->getLocation(); @@ -2867,7 +3206,7 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef, // (The function `getTypeSize` returns the size in bits.) ASTContext &Ctx = SemaRef.Context; if (Ctx.getTypeSize(VariableType) <= 64 * 8 && - (VariableType.isTriviallyCopyableType(Ctx) || + (VariableType.isTriviallyCopyConstructibleType(Ctx) || hasTrivialABIAttr(VariableType))) return; @@ -3000,6 +3339,12 @@ 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)); } + if (S->isConditionVarScope()) { + // We cannot 'continue;' from within a statement expression in the + // initializer of a condition variable because we would jump past the + // initialization of that variable. + return StmtError(Diag(ContinueLoc, diag::err_continue_from_cond_var_init)); + } CheckJumpOutOfSEHFinally(*this, ContinueLoc, *S); return new (Context) ContinueStmt(ContinueLoc); @@ -3020,295 +3365,206 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { return new (Context) BreakStmt(BreakLoc); } -/// Determine whether the given expression is a candidate for -/// copy elision in either a return statement or a throw expression. -/// -/// \param ReturnType If we're determining the copy elision candidate for -/// a return statement, this is the return type of the function. If we're -/// determining the copy elision candidate for a throw expression, this will -/// be a NULL type. +/// Determine whether the given expression might be move-eligible or +/// copy-elidable in either a (co_)return statement or throw expression, +/// without considering function return type, if applicable. /// -/// \param E The expression being returned from the function or block, or -/// being thrown. +/// \param E The expression being returned from the function or block, +/// being thrown, or being co_returned from a coroutine. This expression +/// might be modified by the implementation. /// -/// \param CESK 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). +/// \param Mode Overrides detection of current language mode +/// and uses the rules for C++23. /// -/// \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, - CopyElisionSemanticsKind CESK) { +/// \returns An aggregate which contains the Candidate and isMoveEligible +/// and isCopyElidable methods. If Candidate is non-null, it means +/// isMoveEligible() would be true under the most permissive language standard. +Sema::NamedReturnInfo Sema::getNamedReturnInfo(Expr *&E, + SimplerImplicitMoveMode Mode) { + if (!E) + return NamedReturnInfo(); // - in a return statement in a function [where] ... // ... the expression is the name of a non-volatile automatic object ... - DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParens()); + const auto *DR = dyn_cast<DeclRefExpr>(E->IgnoreParens()); if (!DR || DR->refersToEnclosingVariableOrCapture()) - return nullptr; - VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); + return NamedReturnInfo(); + const auto *VD = dyn_cast<VarDecl>(DR->getDecl()); if (!VD) - return nullptr; - - if (isCopyElisionCandidate(ReturnType, VD, CESK)) - return VD; - return nullptr; + return NamedReturnInfo(); + NamedReturnInfo Res = getNamedReturnInfo(VD); + if (Res.Candidate && !E->isXValue() && + (Mode == SimplerImplicitMoveMode::ForceOn || + (Mode != SimplerImplicitMoveMode::ForceOff && + getLangOpts().CPlusPlus23))) { + E = ImplicitCastExpr::Create(Context, VD->getType().getNonReferenceType(), + CK_NoOp, E, nullptr, VK_XValue, + FPOptionsOverride()); + } + return Res; } -bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, - CopyElisionSemanticsKind CESK) { - QualType VDType = VD->getType(); +/// Determine whether the given NRVO candidate variable is move-eligible or +/// copy-elidable, without considering function return type. +/// +/// \param VD The NRVO candidate variable. +/// +/// \returns An aggregate which contains the Candidate and isMoveEligible +/// and isCopyElidable methods. If Candidate is non-null, it means +/// isMoveEligible() would be true under the most permissive language standard. +Sema::NamedReturnInfo Sema::getNamedReturnInfo(const VarDecl *VD) { + NamedReturnInfo Info{VD, NamedReturnInfo::MoveEligibleAndCopyElidable}; + + // C++20 [class.copy.elision]p3: // - in a return statement in a function with ... - // ... a class return type ... - if (!ReturnType.isNull() && !ReturnType->isDependentType()) { - if (!ReturnType->isRecordType()) - return false; - // ... the same cv-unqualified type as the function return type ... - // When considering moving this expression out, allow dissimilar types. - if (!(CESK & CES_AllowDifferentTypes) && !VDType->isDependentType() && - !Context.hasSameUnqualifiedType(ReturnType, VDType)) - return false; - } + // (other than a function ... parameter) + if (VD->getKind() == Decl::ParmVar) + Info.S = NamedReturnInfo::MoveEligible; + else if (VD->getKind() != Decl::Var) + return NamedReturnInfo(); - // ...object (other than a function or catch-clause parameter)... - if (VD->getKind() != Decl::Var && - !((CESK & CES_AllowParameters) && VD->getKind() == Decl::ParmVar)) - return false; - if (!(CESK & CES_AllowExceptionVariables) && VD->isExceptionVariable()) - return false; + // (other than ... a catch-clause parameter) + if (VD->isExceptionVariable()) + Info.S = NamedReturnInfo::MoveEligible; // ...automatic... - if (!VD->hasLocalStorage()) return false; - - // Return false if VD is a __block variable. We don't want to implicitly move - // out of a __block variable during a return because we cannot assume the - // variable will no longer be used. - if (VD->hasAttr<BlocksAttr>()) return false; + if (!VD->hasLocalStorage()) + return NamedReturnInfo(); - // ...non-volatile... - if (VD->getType().isVolatileQualified()) - return false; + // We don't want to implicitly move out of a __block variable during a return + // because we cannot assume the variable will no longer be used. + if (VD->hasAttr<BlocksAttr>()) + return NamedReturnInfo(); - if (CESK & CES_AllowDifferentTypes) - return true; + QualType VDType = VD->getType(); + if (VDType->isObjectType()) { + // C++17 [class.copy.elision]p3: + // ...non-volatile automatic object... + if (VDType.isVolatileQualified()) + return NamedReturnInfo(); + } else if (VDType->isRValueReferenceType()) { + // C++20 [class.copy.elision]p3: + // ...either a non-volatile object or an rvalue reference to a non-volatile + // object type... + QualType VDReferencedType = VDType.getNonReferenceType(); + if (VDReferencedType.isVolatileQualified() || + !VDReferencedType->isObjectType()) + return NamedReturnInfo(); + Info.S = NamedReturnInfo::MoveEligible; + } else { + return NamedReturnInfo(); + } // Variables with higher required alignment than their type's ABI // alignment cannot use NRVO. - if (!VD->getType()->isDependentType() && VD->hasAttr<AlignedAttr>() && - Context.getDeclAlign(VD) > Context.getTypeAlignInChars(VD->getType())) - return false; + if (!VD->hasDependentAlignment() && + Context.getDeclAlign(VD) > Context.getTypeAlignInChars(VDType)) + Info.S = NamedReturnInfo::MoveEligible; - return true; + return Info; } -/// Try to perform the initialization of a potentially-movable value, -/// which is the operand to a return or throw statement. +/// Updates given NamedReturnInfo's move-eligible and +/// copy-elidable statuses, considering the function +/// return type criteria as applicable to return statements. /// -/// 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 Info The NamedReturnInfo object to update. /// -/// \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. -/// -/// \returns Whether we need to do the second overload resolution. If the first -/// overload resolution fails, or if the first overload resolution succeeds but -/// the selected constructor/operator doesn't match the additional criteria, we -/// need to do the second overload resolution. -static bool TryMoveInitialization(Sema &S, const InitializedEntity &Entity, - const VarDecl *NRVOCandidate, - QualType ResultType, Expr *&Value, - bool ConvertingConstructorsOnly, - bool IsDiagnosticsCheck, ExprResult &Res) { - ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(), - CK_NoOp, Value, VK_XValue, FPOptionsOverride()); - - Expr *InitExpr = &AsRvalue; - - InitializationKind Kind = InitializationKind::CreateCopy( - Value->getBeginLoc(), Value->getBeginLoc()); - - InitializationSequence Seq(S, Entity, Kind, InitExpr); - - bool NeedSecondOverloadResolution = true; - if (!Seq && - (IsDiagnosticsCheck || Seq.getFailedOverloadResult() != OR_Deleted)) { - return NeedSecondOverloadResolution; - } - - for (const InitializationSequence::Step &Step : Seq.steps()) { - if (Step.Kind != InitializationSequence::SK_ConstructorInitialization && - Step.Kind != InitializationSequence::SK_UserConversion) - continue; +/// \param ReturnType This is the return type of the function. +/// \returns The copy elision candidate, in case the initial return expression +/// was copy elidable, or nullptr otherwise. +const VarDecl *Sema::getCopyElisionCandidate(NamedReturnInfo &Info, + QualType ReturnType) { + if (!Info.Candidate) + return nullptr; - FunctionDecl *FD = Step.Function.Function; - if (ConvertingConstructorsOnly) { - if (isa<CXXConstructorDecl>(FD)) { - // C++14 [class.copy]p32: - // [...] 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. - const RValueReferenceType *RRefType = - FD->getParamDecl(0)->getType()->getAs<RValueReferenceType>(); - if (!RRefType) - break; - if (!S.Context.hasSameUnqualifiedType(RRefType->getPointeeType(), - NRVOCandidate->getType())) - break; - } else { - continue; - } - } else { - if (isa<CXXConstructorDecl>(FD)) { - // Check that overload resolution selected a constructor taking an - // rvalue reference. If it selected an lvalue reference, then we - // didn't need to cast this thing to an rvalue in the first place. - if (!isa<RValueReferenceType>(FD->getParamDecl(0)->getType())) - break; - } else if (isa<CXXMethodDecl>(FD)) { - // Check that overload resolution selected a conversion operator - // taking an rvalue reference. - if (cast<CXXMethodDecl>(FD)->getRefQualifier() != RQ_RValue) - break; - } else { - continue; - } - } + auto invalidNRVO = [&] { + Info = NamedReturnInfo(); + return nullptr; + }; - NeedSecondOverloadResolution = false; - // 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, FPOptionsOverride()); + // If we got a non-deduced auto ReturnType, we are in a dependent context and + // there is no point in allowing copy elision since we won't have it deduced + // by the point the VardDecl is instantiated, which is the last chance we have + // of deciding if the candidate is really copy elidable. + if ((ReturnType->getTypeClass() == Type::TypeClass::Auto && + ReturnType->isCanonicalUnqualified()) || + ReturnType->isSpecificBuiltinType(BuiltinType::Dependent)) + return invalidNRVO(); + + if (!ReturnType->isDependentType()) { + // - in a return statement in a function with ... + // ... a class return type ... + if (!ReturnType->isRecordType()) + return invalidNRVO(); - // Complete type-checking the initialization of the return type - // using the constructor we found. - Res = Seq.Perform(S, Entity, Kind, Value); + QualType VDType = Info.Candidate->getType(); + // ... the same cv-unqualified type as the function return type ... + // When considering moving this expression out, allow dissimilar types. + if (!VDType->isDependentType() && + !Context.hasSameUnqualifiedType(ReturnType, VDType)) + Info.S = NamedReturnInfo::MoveEligible; } + return Info.isCopyElidable() ? Info.Candidate : nullptr; +} - return NeedSecondOverloadResolution; +/// Verify that the initialization sequence that was picked for the +/// first overload resolution is permissible under C++98. +/// +/// Reject (possibly converting) constructors not taking an rvalue reference, +/// or user conversion operators which are not ref-qualified. +static bool +VerifyInitializationSequenceCXX98(const Sema &S, + const InitializationSequence &Seq) { + const auto *Step = llvm::find_if(Seq.steps(), [](const auto &Step) { + return Step.Kind == InitializationSequence::SK_ConstructorInitialization || + Step.Kind == InitializationSequence::SK_UserConversion; + }); + if (Step != Seq.step_end()) { + const auto *FD = Step->Function.Function; + if (isa<CXXConstructorDecl>(FD) + ? !FD->getParamDecl(0)->getType()->isRValueReferenceType() + : cast<CXXMethodDecl>(FD)->getRefQualifier() == RQ_None) + return false; + } + return true; } /// Perform the initialization of a potentially-movable value, which /// is the result of return value. /// -/// 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 -Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, - const VarDecl *NRVOCandidate, - QualType ResultType, - Expr *Value, - bool AllowNRVO) { - // 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(); - bool NeedSecondOverloadResolution = true; - - if (AllowNRVO) { - bool AffectedByCWG1579 = false; - - if (!NRVOCandidate) { - NRVOCandidate = getCopyElisionCandidate(ResultType, Value, CES_Default); - if (NRVOCandidate && - !getDiagnostics().isIgnored(diag::warn_return_std_move_in_cxx11, - Value->getExprLoc())) { - const VarDecl *NRVOCandidateInCXX11 = - getCopyElisionCandidate(ResultType, Value, CES_FormerDefault); - AffectedByCWG1579 = (!NRVOCandidateInCXX11); - } - } - - if (NRVOCandidate) { - NeedSecondOverloadResolution = TryMoveInitialization( - *this, Entity, NRVOCandidate, ResultType, Value, true, false, Res); - } - - if (!NeedSecondOverloadResolution && AffectedByCWG1579) { - QualType QT = NRVOCandidate->getType(); - if (QT.getNonReferenceType().getUnqualifiedType().isTriviallyCopyableType( - Context)) { - // Adding 'std::move' around a trivially copyable variable is probably - // pointless. Don't suggest it. - } else { - // Common cases for this are returning unique_ptr<Derived> from a - // function of return type unique_ptr<Base>, or returning T from a - // function of return type Expected<T>. This is totally fine in a - // post-CWG1579 world, but was not fine before. - assert(!ResultType.isNull()); - SmallString<32> Str; - Str += "std::move("; - Str += NRVOCandidate->getDeclName().getAsString(); - Str += ")"; - Diag(Value->getExprLoc(), diag::warn_return_std_move_in_cxx11) - << Value->getSourceRange() << NRVOCandidate->getDeclName() - << ResultType << QT; - Diag(Value->getExprLoc(), diag::note_add_std_move_in_cxx11) - << FixItHint::CreateReplacement(Value->getSourceRange(), Str); - } - } else if (NeedSecondOverloadResolution && - !getDiagnostics().isIgnored(diag::warn_return_std_move, - Value->getExprLoc())) { - const VarDecl *FakeNRVOCandidate = - getCopyElisionCandidate(QualType(), Value, CES_AsIfByStdMove); - if (FakeNRVOCandidate) { - QualType QT = FakeNRVOCandidate->getType(); - if (QT->isLValueReferenceType()) { - // Adding 'std::move' around an lvalue reference variable's name is - // dangerous. Don't suggest it. - } else if (QT.getNonReferenceType() - .getUnqualifiedType() - .isTriviallyCopyableType(Context)) { - // Adding 'std::move' around a trivially copyable variable is probably - // pointless. Don't suggest it. - } else { - ExprResult FakeRes = ExprError(); - Expr *FakeValue = Value; - TryMoveInitialization(*this, Entity, FakeNRVOCandidate, ResultType, - FakeValue, false, true, FakeRes); - if (!FakeRes.isInvalid()) { - bool IsThrow = - (Entity.getKind() == InitializedEntity::EK_Exception); - SmallString<32> Str; - Str += "std::move("; - Str += FakeNRVOCandidate->getDeclName().getAsString(); - Str += ")"; - Diag(Value->getExprLoc(), diag::warn_return_std_move) - << Value->getSourceRange() - << FakeNRVOCandidate->getDeclName() << IsThrow; - Diag(Value->getExprLoc(), diag::note_add_std_move) - << FixItHint::CreateReplacement(Value->getSourceRange(), Str); - } - } - } +/// This routine implements C++20 [class.copy.elision]p3, 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 Sema::PerformMoveOrCopyInitialization( + const InitializedEntity &Entity, const NamedReturnInfo &NRInfo, Expr *Value, + bool SupressSimplerImplicitMoves) { + if (getLangOpts().CPlusPlus && + (!getLangOpts().CPlusPlus23 || SupressSimplerImplicitMoves) && + NRInfo.isMoveEligible()) { + ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(), + CK_NoOp, Value, VK_XValue, FPOptionsOverride()); + Expr *InitExpr = &AsRvalue; + auto Kind = InitializationKind::CreateCopy(Value->getBeginLoc(), + Value->getBeginLoc()); + InitializationSequence Seq(*this, Entity, Kind, InitExpr); + auto Res = Seq.getFailedOverloadResult(); + if ((Res == OR_Success || Res == OR_Deleted) && + (getLangOpts().CPlusPlus11 || + VerifyInitializationSequenceCXX98(*this, Seq))) { + // 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, FPOptionsOverride()); + // Complete type-checking the initialization of the return type + // using the constructor we found. + return Seq.Perform(*this, Entity, Kind, Value); } } - // Either we didn't meet the criteria for treating an lvalue as an rvalue, // above, or overload resolution failed. Either way, we need to try // (again) now with the return value expression as written. - if (NeedSecondOverloadResolution) - Res = PerformCopyInitialization(Entity, SourceLocation(), Value); - - return Res; + return PerformCopyInitialization(Entity, SourceLocation(), Value); } /// Determine whether the declared return type of the specified function @@ -3322,18 +3578,21 @@ static bool hasDeducedReturnType(FunctionDecl *FD) { /// ActOnCapScopeReturnStmt - Utility routine to type-check return statements /// for capturing scopes. /// -StmtResult -Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { +StmtResult Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, + Expr *RetValExp, + NamedReturnInfo &NRInfo, + bool SupressSimplerImplicitMoves) { // If this is the first return we've seen, infer the return type. // [expr.prim.lambda]p4 in C++11; block literals follow the same rules. CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction()); QualType FnRetType = CurCap->ReturnType; LambdaScopeInfo *CurLambda = dyn_cast<LambdaScopeInfo>(CurCap); + if (CurLambda && CurLambda->CallOperator->getType().isNull()) + return StmtError(); bool HasDeducedReturnType = CurLambda && hasDeducedReturnType(CurLambda->CallOperator); - if (ExprEvalContexts.back().Context == - ExpressionEvaluationContext::DiscardedStatement && + if (ExprEvalContexts.back().isDiscardedStatementContext() && (HasDeducedReturnType || CurCap->HasImplicitReturnType)) { if (RetValExp) { ExprResult ER = @@ -3402,7 +3661,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (CurCap->ReturnType.isNull()) CurCap->ReturnType = FnRetType; } - assert(!FnRetType.isNull()); + const VarDecl *NRVOCandidate = getCopyElisionCandidate(NRInfo, FnRetType); if (auto *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) { if (CurBlock->FunctionType->castAs<FunctionType>()->getNoReturnAttr()) { @@ -3425,7 +3684,6 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // Otherwise, verify that this result type matches the previous one. We are // pickier with blocks than for normal functions because we don't have GCC // compatibility to worry about here. - const VarDecl *NRVOCandidate = nullptr; if (FnRetType->isDependentType()) { // Delay processing for now. TODO: there are lots of dependent // types we can conclusively prove aren't void. @@ -3453,20 +3711,16 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. - NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, CES_Strict); - InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, - FnRetType, - NRVOCandidate != nullptr); - ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, - FnRetType, RetValExp); + InitializedEntity Entity = + InitializedEntity::InitializeResult(ReturnLoc, FnRetType); + ExprResult Res = PerformMoveOrCopyInitialization( + Entity, NRInfo, RetValExp, SupressSimplerImplicitMoves); if (Res.isInvalid()) { // FIXME: Cleanup temporaries here, anyway? return StmtError(); } RetValExp = Res.get(); CheckReturnValExpr(RetValExp, FnRetType, ReturnLoc); - } else { - NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, CES_Strict); } if (RetValExp) { @@ -3488,6 +3742,11 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (FunctionScopes.back()->FirstReturnLoc.isInvalid()) FunctionScopes.back()->FirstReturnLoc = ReturnLoc; + if (auto *CurBlock = dyn_cast<BlockScopeInfo>(CurCap); + CurBlock && CurCap->HasImplicitReturnType && RetValExp && + RetValExp->containsErrors()) + CurBlock->TheDecl->setInvalidDecl(); + return Result; } @@ -3536,17 +3795,13 @@ TypeLoc Sema::getReturnTypeLoc(FunctionDecl *FD) const { /// C++1y [dcl.spec.auto]p6. bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, SourceLocation ReturnLoc, - Expr *&RetExpr, - AutoType *AT) { - // If this is the conversion function for a lambda, we choose to deduce it + Expr *RetExpr, const AutoType *AT) { + // If this is the conversion function for a lambda, we choose to deduce its // type from the corresponding call operator, not from the synthesized return // statement within it. See Sema::DeduceReturnType. if (isLambdaConversionOperator(FD)) return false; - TypeLoc OrigResultType = getReturnTypeLoc(FD); - QualType Deduced; - if (RetExpr && isa<InitListExpr>(RetExpr)) { // If the deduction is for a return statement and the initializer is // a braced-init-list, the program is ill-formed. @@ -3566,80 +3821,84 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, return false; } - if (RetExpr) { - // Otherwise, [...] deduce a value for U using the rules of template - // argument deduction. - DeduceAutoResult DAR = DeduceAutoType(OrigResultType, RetExpr, Deduced); - - if (DAR == DAR_Failed && !FD->isInvalidDecl()) - Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure) - << OrigResultType.getType() << RetExpr->getType(); - - if (DAR != DAR_Succeeded) - return true; - - // If a local type is part of the returned type, mark its fields as - // referenced. - LocalTypedefNameReferencer Referencer(*this); - Referencer.TraverseType(RetExpr->getType()); - } else { - // In the case of a return with no operand, the initializer is considered - // to be void(). - // - // Deduction here can only succeed if the return type is exactly 'cv auto' - // or 'decltype(auto)', so just check for that case directly. + TypeLoc OrigResultType = getReturnTypeLoc(FD); + // In the case of a return with no operand, the initializer is considered + // to be void(). + CXXScalarValueInitExpr VoidVal(Context.VoidTy, nullptr, SourceLocation()); + if (!RetExpr) { + // For a function with a deduced result type to return with omitted + // expression, the result type as written must be 'auto' or + // 'decltype(auto)', possibly cv-qualified or constrained, but not + // ref-qualified. if (!OrigResultType.getType()->getAs<AutoType>()) { Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto) - << OrigResultType.getType(); + << OrigResultType.getType(); return true; } - // We always deduce U = void in this case. - Deduced = SubstAutoType(OrigResultType.getType(), Context.VoidTy); - if (Deduced.isNull()) - return true; + RetExpr = &VoidVal; } - // CUDA: Kernel function must have 'void' return type. - if (getLangOpts().CUDA) - if (FD->hasAttr<CUDAGlobalAttr>() && !Deduced->isVoidType()) { - Diag(FD->getLocation(), diag::err_kern_type_not_void_return) - << FD->getType() << FD->getSourceRange(); - return true; + QualType Deduced = AT->getDeducedType(); + { + // Otherwise, [...] deduce a value for U using the rules of template + // argument deduction. + auto RetExprLoc = RetExpr->getExprLoc(); + TemplateDeductionInfo Info(RetExprLoc); + SourceLocation TemplateSpecLoc; + if (RetExpr->getType() == Context.OverloadTy) { + auto FindResult = OverloadExpr::find(RetExpr); + if (FindResult.Expression) + TemplateSpecLoc = FindResult.Expression->getNameLoc(); } - - // If a function with a declared return type that contains a placeholder type - // 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. - 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( - DeducedT); - CanQualType NewDeducedType = Context.getCanonicalFunctionResultType( - NewAT->getDeducedType()); - if (!FD->isDependentContext() && OldDeducedType != NewDeducedType) { + TemplateSpecCandidateSet FailedTSC(TemplateSpecLoc); + TemplateDeductionResult Res = DeduceAutoType( + OrigResultType, RetExpr, Deduced, Info, /*DependentDeduction=*/false, + /*IgnoreConstraints=*/false, &FailedTSC); + if (Res != TDK_Success && FD->isInvalidDecl()) + return true; + switch (Res) { + case TDK_Success: + break; + case TDK_AlreadyDiagnosed: + return true; + case TDK_Inconsistent: { + // If a function with a declared return type that contains a placeholder + // type 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. const LambdaScopeInfo *LambdaSI = getCurLambda(); - if (LambdaSI && LambdaSI->HasImplicitReturnType) { + if (LambdaSI && LambdaSI->HasImplicitReturnType) Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible) - << NewAT->getDeducedType() << DeducedT - << true /*IsLambda*/; - } else { + << Info.SecondArg << Info.FirstArg << true /*IsLambda*/; + else Diag(ReturnLoc, diag::err_auto_fn_different_deductions) - << (AT->isDecltypeAuto() ? 1 : 0) - << NewAT->getDeducedType() << DeducedT; - } + << (AT->isDecltypeAuto() ? 1 : 0) << Info.SecondArg + << Info.FirstArg; + return true; + } + default: + Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure) + << OrigResultType.getType() << RetExpr->getType(); + FailedTSC.NoteCandidates(*this, RetExprLoc); return true; } - } else if (!FD->isInvalidDecl()) { + } + + // If a local type is part of the returned type, mark its fields as + // referenced. + LocalTypedefNameReferencer(*this).TraverseType(RetExpr->getType()); + + // CUDA: Kernel function must have 'void' return type. + if (getLangOpts().CUDA && FD->hasAttr<CUDAGlobalAttr>() && + !Deduced->isVoidType()) { + Diag(FD->getLocation(), diag::err_kern_type_not_void_return) + << FD->getType() << FD->getSourceRange(); + return true; + } + + if (!FD->isInvalidDecl() && AT->getDeducedType() != Deduced) // Update all declarations of the function to have the deduced return type. Context.adjustDeducedFunctionResultType(FD, Deduced); - } return false; } @@ -3653,30 +3912,53 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, RetValExp, nullptr, /*RecoverUncorrectedTypos=*/true); if (RetVal.isInvalid()) return StmtError(); - StmtResult R = BuildReturnStmt(ReturnLoc, RetVal.get()); - if (R.isInvalid() || ExprEvalContexts.back().Context == - ExpressionEvaluationContext::DiscardedStatement) + StmtResult R = + BuildReturnStmt(ReturnLoc, RetVal.get(), /*AllowRecovery=*/true); + if (R.isInvalid() || ExprEvalContexts.back().isDiscardedStatementContext()) return R; - if (VarDecl *VD = - const_cast<VarDecl*>(cast<ReturnStmt>(R.get())->getNRVOCandidate())) { - CurScope->addNRVOCandidate(VD); - } else { - CurScope->setNoNRVO(); - } + VarDecl *VD = + const_cast<VarDecl *>(cast<ReturnStmt>(R.get())->getNRVOCandidate()); + + CurScope->updateNRVOCandidate(VD); CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent()); return R; } -StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { +static bool CheckSimplerImplicitMovesMSVCWorkaround(const Sema &S, + const Expr *E) { + if (!E || !S.getLangOpts().CPlusPlus23 || !S.getLangOpts().MSVCCompat) + return false; + const Decl *D = E->getReferencedDeclOfCallee(); + if (!D || !S.SourceMgr.isInSystemHeader(D->getLocation())) + return false; + for (const DeclContext *DC = D->getDeclContext(); DC; DC = DC->getParent()) { + if (DC->isStdNamespace()) + return true; + } + return false; +} + +StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, + bool AllowRecovery) { // Check for unexpanded parameter packs. if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) return StmtError(); + // HACK: We suppress simpler implicit move here in msvc compatibility mode + // just as a temporary work around, as the MSVC STL has issues with + // this change. + bool SupressSimplerImplicitMoves = + CheckSimplerImplicitMovesMSVCWorkaround(*this, RetValExp); + NamedReturnInfo NRInfo = getNamedReturnInfo( + RetValExp, SupressSimplerImplicitMoves ? SimplerImplicitMoveMode::ForceOff + : SimplerImplicitMoveMode::Normal); + if (isa<CapturingScopeInfo>(getCurFunction())) - return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp); + return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp, NRInfo, + SupressSimplerImplicitMoves); QualType FnRetType; QualType RelatedRetType; @@ -3714,10 +3996,17 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } else // If we don't have a function/method context, bail. return StmtError(); + if (RetValExp) { + const auto *ATy = dyn_cast<ArrayType>(RetValExp->getType()); + if (ATy && ATy->getElementType().isWebAssemblyReferenceType()) { + Diag(ReturnLoc, diag::err_wasm_table_art) << 1; + return StmtError(); + } + } + // C++1z: discarded return statements are not considered when deducing a // return type. - if (ExprEvalContexts.back().Context == - ExpressionEvaluationContext::DiscardedStatement && + if (ExprEvalContexts.back().isDiscardedStatementContext() && FnRetType->getContainedAutoType()) { if (RetValExp) { ExprResult ER = @@ -3738,23 +4027,38 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // If we've already decided this function is invalid, e.g. because // we saw a `return` whose expression had an error, don't keep // trying to deduce its return type. - if (FD->isInvalidDecl()) - return StmtError(); - if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { + // (Some return values may be needlessly wrapped in RecoveryExpr). + if (FD->isInvalidDecl() || + DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { FD->setInvalidDecl(); - return StmtError(); + if (!AllowRecovery) + return StmtError(); + // The deduction failure is diagnosed and marked, try to recover. + if (RetValExp) { + // Wrap return value with a recovery expression of the previous type. + // If no deduction yet, use DependentTy. + auto Recovery = CreateRecoveryExpr( + RetValExp->getBeginLoc(), RetValExp->getEndLoc(), RetValExp, + AT->isDeduced() ? FnRetType : QualType()); + if (Recovery.isInvalid()) + return StmtError(); + RetValExp = Recovery.get(); + } else { + // Nothing to do: a ReturnStmt with no value is fine recovery. + } } else { FnRetType = FD->getReturnType(); } } } + const VarDecl *NRVOCandidate = getCopyElisionCandidate(NRInfo, FnRetType); bool HasDependentReturnType = FnRetType->isDependentType(); ReturnStmt *Result = nullptr; if (FnRetType->isVoidType()) { if (RetValExp) { - if (isa<InitListExpr>(RetValExp)) { + if (auto *ILE = dyn_cast<InitListExpr>(RetValExp)) { // We simply never allow init lists as the return value of void // functions. This is compatible because this was never allowed before, // so there's no legacy code to deal with. @@ -3770,8 +4074,12 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { Diag(ReturnLoc, diag::err_return_init_list) << CurDecl << FunctionKind << RetValExp->getSourceRange(); - // Drop the expression. - RetValExp = nullptr; + // Preserve the initializers in the AST. + RetValExp = AllowRecovery + ? CreateRecoveryExpr(ILE->getLBraceLoc(), + ILE->getRBraceLoc(), ILE->inits()) + .get() + : nullptr; } else if (!RetValExp->isTypeDependent()) { // C99 6.8.6.4p1 (ext_ since GCC warns) unsigned D = diag::ext_return_has_expr; @@ -3830,7 +4138,9 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } else if (!RetValExp && !HasDependentReturnType) { FunctionDecl *FD = getCurFunctionDecl(); - if (getLangOpts().CPlusPlus11 && FD && FD->isConstexpr()) { + if ((FD && FD->isInvalidDecl()) || FnRetType->containsErrors()) { + // The intended return type might have been "void", so don't warn. + } else if (getLangOpts().CPlusPlus11 && FD && FD->isConstexpr()) { // C++11 [stmt.return]p2 Diag(ReturnLoc, diag::err_constexpr_return_missing_expr) << FD << FD->isConsteval(); @@ -3854,8 +4164,6 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { /* NRVOCandidate=*/nullptr); } else { assert(RetValExp || HasDependentReturnType); - const VarDecl *NRVOCandidate = nullptr; - QualType RetType = RelatedRetType.isNull() ? FnRetType : RelatedRetType; // C99 6.8.6.4p3(136): The return statement is not an assignment. The @@ -3864,15 +4172,15 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // In C++ the return statement is handled via a copy initialization, // the C version of which boils down to CheckSingleAssignmentConstraints. - if (RetValExp) - NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, CES_Strict); if (!HasDependentReturnType && !RetValExp->isTypeDependent()) { // we have a non-void function with an expression, continue checking - InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, - RetType, - NRVOCandidate != nullptr); - ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, - RetType, RetValExp); + InitializedEntity Entity = + InitializedEntity::InitializeResult(ReturnLoc, RetType); + ExprResult Res = PerformMoveOrCopyInitialization( + Entity, NRInfo, RetValExp, SupressSimplerImplicitMoves); + if (Res.isInvalid() && AllowRecovery) + Res = CreateRecoveryExpr(RetValExp->getBeginLoc(), + RetValExp->getEndLoc(), RetValExp, RetType); if (Res.isInvalid()) { // FIXME: Clean up temporaries here anyway? return StmtError(); @@ -3941,7 +4249,14 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, if (!getLangOpts().ObjCExceptions) Diag(AtLoc, diag::err_objc_exceptions_disabled) << "@try"; - setFunctionHasBranchProtectedScope(); + // Objective-C try is incompatible with SEH __try. + sema::FunctionScopeInfo *FSI = getCurFunction(); + if (FSI->FirstSEHTryLoc.isValid()) { + Diag(AtLoc, diag::err_mixing_cxx_try_seh_try) << 1; + Diag(FSI->FirstSEHTryLoc, diag::note_conflicting_try_here) << "'__try'"; + } + + FSI->setHasObjCTry(AtLoc); unsigned NumCatchStmts = CatchStmts.size(); return ObjCAtTryStmt::Create(Context, AtLoc, Try, CatchStmts.data(), NumCatchStmts, Finally); @@ -4071,9 +4386,9 @@ public: if (QT->isPointerType()) IsPointer = true; + QT = QT.getUnqualifiedType(); if (IsPointer || QT->isReferenceType()) QT = QT->getPointeeType(); - QT = QT.getUnqualifiedType(); } /// Used when creating a CatchHandlerType from a base class type; pretends the @@ -4121,32 +4436,42 @@ template <> struct DenseMapInfo<CatchHandlerType> { namespace { class CatchTypePublicBases { - ASTContext &Ctx; - const llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> &TypesToCheck; - const bool CheckAgainstPointer; + const llvm::DenseMap<QualType, CXXCatchStmt *> &TypesToCheck; CXXCatchStmt *FoundHandler; - CanQualType FoundHandlerType; + QualType FoundHandlerType; + QualType TestAgainstType; public: - CatchTypePublicBases( - ASTContext &Ctx, - const llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> &T, bool C) - : Ctx(Ctx), TypesToCheck(T), CheckAgainstPointer(C), - FoundHandler(nullptr) {} + CatchTypePublicBases(const llvm::DenseMap<QualType, CXXCatchStmt *> &T, + QualType QT) + : TypesToCheck(T), FoundHandler(nullptr), TestAgainstType(QT) {} CXXCatchStmt *getFoundHandler() const { return FoundHandler; } - CanQualType getFoundHandlerType() const { return FoundHandlerType; } + QualType getFoundHandlerType() const { return FoundHandlerType; } bool operator()(const CXXBaseSpecifier *S, CXXBasePath &) { if (S->getAccessSpecifier() == AccessSpecifier::AS_public) { - CatchHandlerType Check(S->getType(), CheckAgainstPointer); + QualType Check = S->getType().getCanonicalType(); const auto &M = TypesToCheck; auto I = M.find(Check); if (I != M.end()) { - FoundHandler = I->second; - FoundHandlerType = Ctx.getCanonicalType(S->getType()); - return true; + // We're pretty sure we found what we need to find. However, we still + // need to make sure that we properly compare for pointers and + // references, to handle cases like: + // + // } catch (Base *b) { + // } catch (Derived &d) { + // } + // + // where there is a qualification mismatch that disqualifies this + // handler as a potential problem. + if (I->second->getCaughtType()->isPointerType() == + TestAgainstType->isPointerType()) { + FoundHandler = I->second; + FoundHandlerType = Check; + return true; + } } } return false; @@ -4158,13 +4483,22 @@ public: /// handlers and creates a try statement from them. StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, ArrayRef<Stmt *> Handlers) { - // Don't report an error if 'try' is used in system headers. - if (!getLangOpts().CXXExceptions && + const llvm::Triple &T = Context.getTargetInfo().getTriple(); + const bool IsOpenMPGPUTarget = + getLangOpts().OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN()); + // Don't report an error if 'try' is used in system headers or in an OpenMP + // target region compiled for a GPU architecture. + if (!IsOpenMPGPUTarget && !getLangOpts().CXXExceptions && !getSourceManager().isInSystemHeader(TryLoc) && !getLangOpts().CUDA) { // Delay error emission for the OpenMP device code. targetDiag(TryLoc, diag::err_exceptions_disabled) << "try"; } + // In OpenMP target regions, we assume that catch is never reached on GPU + // targets. + if (IsOpenMPGPUTarget) + targetDiag(TryLoc, diag::warn_try_not_valid_on_target) << T.str(); + // Exceptions aren't allowed in CUDA device code. if (getLangOpts().CUDA) CUDADiagIfDeviceCode(TryLoc, diag::err_cuda_device_exceptions) @@ -4177,7 +4511,7 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, // C++ try is incompatible with SEH __try. if (!getLangOpts().Borland && FSI->FirstSEHTryLoc.isValid()) { - Diag(TryLoc, diag::err_mixing_cxx_try_seh_try); + Diag(TryLoc, diag::err_mixing_cxx_try_seh_try) << 0; Diag(FSI->FirstSEHTryLoc, diag::note_conflicting_try_here) << "'__try'"; } @@ -4185,6 +4519,7 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, assert(!Handlers.empty() && "The parser shouldn't call this if there are no handlers."); + llvm::DenseMap<QualType, CXXCatchStmt *> HandledBaseTypes; llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> HandledTypes; for (unsigned i = 0; i < NumHandlers; ++i) { CXXCatchStmt *H = cast<CXXCatchStmt>(Handlers[i]); @@ -4202,8 +4537,7 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, // 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()); + CatchHandlerType HandlerCHT = H->getCaughtType().getCanonicalType(); // 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 @@ -4219,10 +4553,12 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, // as the original type. CXXBasePaths Paths; Paths.setOrigin(RD); - CatchTypePublicBases CTPB(Context, HandledTypes, HandlerCHT.isPointer()); + CatchTypePublicBases CTPB(HandledBaseTypes, + H->getCaughtType().getCanonicalType()); if (RD->lookupInBases(CTPB, Paths)) { const CXXCatchStmt *Problem = CTPB.getFoundHandler(); - if (!Paths.isAmbiguous(CTPB.getFoundHandlerType())) { + if (!Paths.isAmbiguous( + CanQualType::CreateUnsafe(CTPB.getFoundHandlerType()))) { Diag(H->getExceptionDecl()->getTypeSpecStartLoc(), diag::warn_exception_caught_by_earlier_handler) << H->getCaughtType(); @@ -4231,11 +4567,16 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, << Problem->getCaughtType(); } } + // Strip the qualifiers here because we're going to be comparing this + // type to the base type specifiers of a class, which are ignored in a + // base specifier per [class.derived.general]p2. + HandledBaseTypes[Underlying.getUnqualifiedType()] = H; } // 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)); + auto R = HandledTypes.insert( + std::make_pair(H->getCaughtType().getCanonicalType(), H)); if (!R.second) { const CXXCatchStmt *Problem = R.first->second; Diag(H->getExceptionDecl()->getTypeSpecStartLoc(), @@ -4249,7 +4590,8 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, FSI->setHasCXXTry(TryLoc); - return CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers); + return CXXTryStmt::Create(Context, TryLoc, cast<CompoundStmt>(TryBlock), + Handlers); } StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, @@ -4261,9 +4603,12 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, // 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'"; + if (FSI->FirstCXXOrObjCTryLoc.isValid()) { + Diag(TryLoc, diag::err_mixing_cxx_try_seh_try) << FSI->FirstTryType; + Diag(FSI->FirstCXXOrObjCTryLoc, diag::note_conflicting_try_here) + << (FSI->FirstTryType == sema::FunctionScopeInfo::TryLocIsCXX + ? "'try'" + : "'@try'"); } } @@ -4357,10 +4702,11 @@ Sema::CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc, RecordDecl *RD = nullptr; if (getLangOpts().CPlusPlus) - RD = CXXRecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, + RD = CXXRecordDecl::Create(Context, TagTypeKind::Struct, DC, Loc, Loc, /*Id=*/nullptr); else - RD = RecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/nullptr); + RD = RecordDecl::Create(Context, TagTypeKind::Struct, DC, Loc, Loc, + /*Id=*/nullptr); RD->setCapturedRecord(); DC->addDecl(RD); @@ -4404,11 +4750,11 @@ buildCapturedStmtCaptureList(Sema &S, CapturedRegionScopeInfo *RSI, if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) S.setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel); - Captures.push_back(CapturedStmt::Capture(Cap.getLocation(), - Cap.isReferenceCapture() - ? CapturedStmt::VCK_ByRef - : CapturedStmt::VCK_ByCopy, - Cap.getVariable())); + Captures.push_back(CapturedStmt::Capture( + Cap.getLocation(), + Cap.isReferenceCapture() ? CapturedStmt::VCK_ByRef + : CapturedStmt::VCK_ByCopy, + cast<VarDecl>(Cap.getVariable()))); } CaptureInits.push_back(Init.get()); } @@ -4427,7 +4773,7 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD)); auto *Param = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType, - ImplicitParamDecl::CapturedContext); + ImplicitParamKind::CapturedContext); DC->addDecl(Param); CD->setContextParam(0, Param); @@ -4442,6 +4788,7 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, PushExpressionEvaluationContext( ExpressionEvaluationContext::PotentiallyEvaluated); + ExprEvalContexts.back().InImmediateEscalatingFunctionContext = false; } void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, @@ -4467,7 +4814,7 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, .withRestrict(); auto *Param = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType, - ImplicitParamDecl::CapturedContext); + ImplicitParamKind::CapturedContext); DC->addDecl(Param); CD->setContextParam(ParamNum, Param); ContextIsFound = true; @@ -4475,7 +4822,7 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, IdentifierInfo *ParamName = &Context.Idents.get(I->first); auto *Param = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, I->second, - ImplicitParamDecl::CapturedContext); + ImplicitParamKind::CapturedContext); DC->addDecl(Param); CD->setParam(ParamNum, Param); } @@ -4487,7 +4834,7 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD)); auto *Param = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType, - ImplicitParamDecl::CapturedContext); + ImplicitParamKind::CapturedContext); DC->addDecl(Param); CD->setContextParam(ParamNum, Param); } |