diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/ScopeInfo.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCoroutine.cpp | 231 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExceptionSpec.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 20 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 83 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 78 |
7 files changed, 352 insertions, 65 deletions
diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp index ba8c3642bc8..6a400a2efe5 100644 --- a/clang/lib/Sema/ScopeInfo.cpp +++ b/clang/lib/Sema/ScopeInfo.cpp @@ -33,11 +33,13 @@ void FunctionScopeInfo::Clear() { ObjCWarnForNoDesignatedInitChain = false; ObjCIsSecondaryInit = false; ObjCWarnForNoInitDelegation = false; + FirstReturnLoc = SourceLocation(); FirstCXXTryLoc = SourceLocation(); FirstSEHTryLoc = SourceLocation(); SwitchStack.clear(); Returns.clear(); + CoroutineStmts.clear(); ErrorTrap.reset(); PossiblyUnreachableDiags.clear(); WeakObjectUses.clear(); diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 6545b6709a2..a2a79001f0d 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -12,12 +12,89 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" +#include "clang/AST/Decl.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtCXX.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Overload.h" using namespace clang; using namespace sema; +/// Look up the std::coroutine_traits<...>::promise_type for the given +/// function type. +static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, + SourceLocation Loc) { + // FIXME: Cache std::coroutine_traits once we've found it. + NamespaceDecl *Std = S.getStdNamespace(); + if (!Std) { + S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found); + return QualType(); + } + + LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_traits"), + Loc, Sema::LookupOrdinaryName); + if (!S.LookupQualifiedName(Result, Std)) { + S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found); + return QualType(); + } + + ClassTemplateDecl *CoroTraits = Result.getAsSingle<ClassTemplateDecl>(); + if (!CoroTraits) { + Result.suppressDiagnostics(); + // We found something weird. Complain about the first thing we found. + NamedDecl *Found = *Result.begin(); + S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits); + return QualType(); + } + + // Form template argument list for coroutine_traits<R, P1, P2, ...>. + TemplateArgumentListInfo Args(Loc, Loc); + Args.addArgument(TemplateArgumentLoc( + TemplateArgument(FnType->getReturnType()), + S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), Loc))); + for (QualType T : FnType->getParamTypes()) + Args.addArgument(TemplateArgumentLoc( + TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, Loc))); + + // Build the template-id. + QualType CoroTrait = + S.CheckTemplateIdType(TemplateName(CoroTraits), Loc, Args); + if (CoroTrait.isNull()) + return QualType(); + if (S.RequireCompleteType(Loc, CoroTrait, + diag::err_coroutine_traits_missing_specialization)) + return QualType(); + + CXXRecordDecl *RD = CoroTrait->getAsCXXRecordDecl(); + assert(RD && "specialization of class template is not a class?"); + + // Look up the ::promise_type member. + LookupResult R(S, &S.PP.getIdentifierTable().get("promise_type"), Loc, + Sema::LookupOrdinaryName); + S.LookupQualifiedName(R, RD); + auto *Promise = R.getAsSingle<TypeDecl>(); + if (!Promise) { + S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_found) + << RD; + return QualType(); + } + + // The promise type is required to be a class type. + QualType PromiseType = S.Context.getTypeDeclType(Promise); + if (!PromiseType->getAsCXXRecordDecl()) { + S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_class) + << PromiseType; + return QualType(); + } + + return PromiseType; +} + +/// Check that this is a context in which a coroutine suspension can appear. static FunctionScopeInfo * checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) { // 'co_await' and 'co_yield' are permitted in unevaluated operands. + // FIXME: Not in 'noexcept'. if (S.isUnevaluatedContext()) return nullptr; @@ -42,36 +119,143 @@ checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) { } else { auto *ScopeInfo = S.getCurFunction(); assert(ScopeInfo && "missing function scope for function"); + + // If we don't have a promise variable, build one now. + if (!ScopeInfo->CoroutinePromise && !FD->getType()->isDependentType()) { + QualType T = + lookupPromiseType(S, FD->getType()->castAs<FunctionProtoType>(), Loc); + if (T.isNull()) + return nullptr; + + // Create and default-initialize the promise. + ScopeInfo->CoroutinePromise = + VarDecl::Create(S.Context, FD, FD->getLocation(), FD->getLocation(), + &S.PP.getIdentifierTable().get("__promise"), T, + S.Context.getTrivialTypeSourceInfo(T, Loc), SC_None); + S.CheckVariableDeclarationType(ScopeInfo->CoroutinePromise); + if (!ScopeInfo->CoroutinePromise->isInvalidDecl()) + S.ActOnUninitializedDecl(ScopeInfo->CoroutinePromise, false); + } + return ScopeInfo; } return nullptr; } -ExprResult Sema::ActOnCoawaitExpr(SourceLocation Loc, Expr *E) { - auto *Context = checkCoroutineContext(*this, Loc, "co_await"); - ExprResult Res = ExprError(); +/// Build a call to 'operator co_await' if there is a suitable operator for +/// the given expression. +static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S, + SourceLocation Loc, Expr *E) { + UnresolvedSet<16> Functions; + SemaRef.LookupOverloadedOperatorName(OO_Coawait, S, E->getType(), QualType(), + Functions); + return SemaRef.CreateOverloadedUnaryOp(Loc, UO_Coawait, Functions, E); +} + +struct ReadySuspendResumeResult { + bool IsInvalid; + Expr *Results[3]; +}; + +/// Build calls to await_ready, await_suspend, and await_resume for a co_await +/// expression. +static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, SourceLocation Loc, + Expr *E) { + // Assume invalid until we see otherwise. + ReadySuspendResumeResult Calls = {true, {}}; + + const StringRef Funcs[] = {"await_ready", "await_suspend", "await_resume"}; + for (size_t I = 0, N = llvm::array_lengthof(Funcs); I != N; ++I) { + DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Funcs[I]), Loc); + + Expr *Operand = new (S.Context) OpaqueValueExpr( + Loc, E->getType(), E->getValueKind(), E->getObjectKind(), E); + + // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&. + CXXScopeSpec SS; + ExprResult Result = S.BuildMemberReferenceExpr( + Operand, Operand->getType(), Loc, /*IsPtr=*/false, SS, + SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr, + /*Scope=*/nullptr); + if (Result.isInvalid()) + return Calls; - if (Context && !Res.isInvalid()) - Context->CoroutineStmts.push_back(Res.get()); + // FIXME: Pass coroutine handle to await_suspend. + Result = S.ActOnCallExpr(nullptr, Result.get(), Loc, None, Loc, nullptr); + if (Result.isInvalid()) + return Calls; + Calls.Results[I] = Result.get(); + } + + Calls.IsInvalid = false; + return Calls; +} + +ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) { + ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E); + if (Awaitable.isInvalid()) + return ExprError(); + return BuildCoawaitExpr(Loc, Awaitable.get()); +} +ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) { + auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await"); + + if (E->getType()->isDependentType()) { + Expr *Res = new (Context) CoawaitExpr(Loc, Context.DependentTy, E); + if (Coroutine) + Coroutine->CoroutineStmts.push_back(Res); + return Res; + } + + if (E->getType()->isPlaceholderType()) { + ExprResult R = CheckPlaceholderExpr(E); + if (R.isInvalid()) return ExprError(); + E = R.get(); + } + + // FIXME: If E is a prvalue, create a temporary. + // FIXME: If E is an xvalue, convert to lvalue. + + // Build the await_ready, await_suspend, await_resume calls. + ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E); + if (RSS.IsInvalid) + return ExprError(); + + Expr *Res = new (Context) CoawaitExpr(Loc, E, RSS.Results[0], RSS.Results[1], + RSS.Results[2]); + if (Coroutine) + Coroutine->CoroutineStmts.push_back(Res); return Res; } -ExprResult Sema::ActOnCoyieldExpr(SourceLocation Loc, Expr *E) { - auto *Context = checkCoroutineContext(*this, Loc, "co_yield"); - ExprResult Res = ExprError(); +ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) { + // FIXME: Build yield_value call. + ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E); + if (Awaitable.isInvalid()) + return ExprError(); + return BuildCoyieldExpr(Loc, Awaitable.get()); +} +ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) { + auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield"); - if (Context && !Res.isInvalid()) - Context->CoroutineStmts.push_back(Res.get()); + // FIXME: Build await_* calls. + Expr *Res = new (Context) CoyieldExpr(Loc, Context.VoidTy, E); + if (Coroutine) + Coroutine->CoroutineStmts.push_back(Res); return Res; } StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) { - auto *Context = checkCoroutineContext(*this, Loc, "co_return"); - StmtResult Res = StmtError(); + return BuildCoreturnStmt(Loc, E); +} +StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) { + auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return"); - if (Context && !Res.isInvalid()) - Context->CoroutineStmts.push_back(Res.get()); + // FIXME: Build return_* calls. + Stmt *Res = new (Context) CoreturnStmt(Loc, E); + if (Coroutine) + Coroutine->CoroutineStmts.push_back(Res); return Res; } @@ -81,26 +265,25 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *Body) { // Coroutines [stmt.return]p1: // A return statement shall not appear in a coroutine. - if (!Fn->Returns.empty()) { - Diag(Fn->Returns.front()->getLocStart(), diag::err_return_in_coroutine); + if (Fn->FirstReturnLoc.isValid()) { + Diag(Fn->FirstReturnLoc, diag::err_return_in_coroutine); auto *First = Fn->CoroutineStmts[0]; Diag(First->getLocStart(), diag::note_declared_coroutine_here) - << 0; // FIXME: Indicate the kind here + << (isa<CoawaitExpr>(First) ? 0 : + isa<CoyieldExpr>(First) ? 1 : 2); } bool AnyCoawaits = false; bool AnyCoyields = false; for (auto *CoroutineStmt : Fn->CoroutineStmts) { - (void)CoroutineStmt; - AnyCoawaits = AnyCoyields = true; // FIXME + AnyCoawaits |= isa<CoawaitExpr>(CoroutineStmt); + AnyCoyields |= isa<CoyieldExpr>(CoroutineStmt); } if (!AnyCoawaits && !AnyCoyields) Diag(Fn->CoroutineStmts.front()->getLocStart(), - diag::ext_coroutine_without_coawait_coyield); + diag::ext_coroutine_without_co_await_co_yield); - // FIXME: If we have a deduced return type, resolve it now. - // FIXME: Compute the promise type. - // FIXME: Perform analysis of initial and final suspend, and set_exception call. - // FIXME: Complete the semantic analysis of the CoroutineStmts. + // FIXME: Perform analysis of initial and final suspend, + // and set_exception call. } diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index a18824f1552..f993a28a13e 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1063,8 +1063,10 @@ CanThrowResult Sema::canThrow(const Expr *E) { // Many other things have subexpressions, so we have to test those. // Some are simple: + case Expr::CoawaitExprClass: case Expr::ConditionalOperatorClass: case Expr::CompoundLiteralExprClass: + case Expr::CoyieldExprClass: case Expr::CXXConstCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::CXXStdInitializerListExprClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index badb2ef118f..857925da99c 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10901,6 +10901,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, } break; case UO_Extension: + case UO_Coawait: resultType = Input.get()->getType(); VK = Input.get()->getValueKind(); OK = Input.get()->getObjectKind(); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index d4a220037ec..084e25a1cbb 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -8228,15 +8228,16 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, case OO_Array_New: case OO_Array_Delete: case OO_Call: - case OO_Coawait: llvm_unreachable( "Special operators don't use AddBuiltinOperatorCandidates"); case OO_Comma: case OO_Arrow: + case OO_Coawait: // C++ [over.match.oper]p3: - // -- For the operator ',', the unary operator '&', or the - // operator '->', the built-in candidates set is empty. + // -- For the operator ',', the unary operator '&', the + // operator '->', or the operator 'co_await', the + // built-in candidates set is empty. break; case OO_Plus: // '+' is either unary or binary @@ -12481,13 +12482,14 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, /// otherwise CallExpr is set to ExprError() and some non-success value /// is returned. Sema::ForRangeStatus -Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc, - SourceLocation RangeLoc, VarDecl *Decl, - BeginEndFunction BEF, +Sema::BuildForRangeBeginEndCall(SourceLocation Loc, + SourceLocation RangeLoc, const DeclarationNameInfo &NameInfo, LookupResult &MemberLookup, OverloadCandidateSet *CandidateSet, Expr *Range, ExprResult *CallExpr) { + Scope *S = nullptr; + CandidateSet->clear(); if (!MemberLookup.empty()) { ExprResult MemberRef = @@ -12499,15 +12501,11 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc, /*TemplateArgs=*/nullptr, S); if (MemberRef.isInvalid()) { *CallExpr = ExprError(); - Diag(Range->getLocStart(), diag::note_in_for_range) - << RangeLoc << BEF << Range->getType(); return FRS_DiagnosticIssued; } *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, None, Loc, nullptr); if (CallExpr->isInvalid()) { *CallExpr = ExprError(); - Diag(Range->getLocStart(), diag::note_in_for_range) - << RangeLoc << BEF << Range->getType(); return FRS_DiagnosticIssued; } } else { @@ -12538,8 +12536,6 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc, /*AllowTypoCorrection=*/false); if (CallExpr->isInvalid() || OverloadResult != OR_Success) { *CallExpr = ExprError(); - Diag(Range->getLocStart(), diag::note_in_for_range) - << RangeLoc << BEF << Range->getType(); return FRS_DiagnosticIssued; } } diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index fec12000950..f8668c38932 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -1859,13 +1859,19 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, } namespace { +// An enum to represent whether something is dealing with a call to begin() +// or a call to end() in a range-based for loop. +enum BeginEndFunction { + BEF_begin, + BEF_end +}; /// Produce a note indicating which begin/end function was implicitly called /// by a C++11 for-range statement. This is often not obvious from the code, /// nor from the diagnostics produced when analysing the implicit expressions /// required in a for-range statement. void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E, - Sema::BeginEndFunction BEF) { + BeginEndFunction BEF) { CallExpr *CE = dyn_cast<CallExpr>(E); if (!CE) return; @@ -1923,10 +1929,11 @@ static bool ObjCEnumerationCollection(Expr *Collection) { /// /// The body of the loop is not available yet, since it cannot be analysed until /// we have determined the type of the for-range-declaration. -StmtResult -Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, - Stmt *First, SourceLocation ColonLoc, Expr *Range, - SourceLocation RParenLoc, BuildForRangeKind Kind) { +StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, + SourceLocation CoawaitLoc, Stmt *First, + SourceLocation ColonLoc, Expr *Range, + SourceLocation RParenLoc, + BuildForRangeKind Kind) { if (!First) return StmtError(); @@ -1950,7 +1957,7 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, // Coroutines: 'for co_await' implicitly co_awaits its range. if (CoawaitLoc.isValid()) { - ExprResult Coawait = ActOnCoawaitExpr(CoawaitLoc, Range); + ExprResult Coawait = ActOnCoawaitExpr(S, CoawaitLoc, Range); if (Coawait.isInvalid()) return StmtError(); Range = Coawait.get(); } @@ -1990,7 +1997,7 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, /// BeginExpr and EndExpr are set and FRS_Success is returned on success; /// CandidateSet and BEF are set and some non-success value is returned on /// failure. -static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S, +static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange, QualType RangeType, VarDecl *BeginVar, @@ -1999,7 +2006,7 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S, OverloadCandidateSet *CandidateSet, ExprResult *BeginExpr, ExprResult *EndExpr, - Sema::BeginEndFunction *BEF) { + BeginEndFunction *BEF) { DeclarationNameInfo BeginNameInfo( &SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc); DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"), @@ -2020,7 +2027,7 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S, if (BeginMemberLookup.empty() != EndMemberLookup.empty()) { SourceLocation RangeLoc = BeginVar->getLocation(); - *BEF = BeginMemberLookup.empty() ? Sema::BEF_end : Sema::BEF_begin; + *BEF = BeginMemberLookup.empty() ? BEF_end : BEF_begin; SemaRef.Diag(RangeLoc, diag::err_for_range_member_begin_end_mismatch) << RangeLoc << BeginRange->getType() << *BEF; @@ -2034,29 +2041,35 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S, } - *BEF = Sema::BEF_begin; + *BEF = BEF_begin; Sema::ForRangeStatus RangeStatus = - SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, BeginVar, - Sema::BEF_begin, BeginNameInfo, + SemaRef.BuildForRangeBeginEndCall(ColonLoc, ColonLoc, BeginNameInfo, BeginMemberLookup, CandidateSet, BeginRange, BeginExpr); - if (RangeStatus != Sema::FRS_Success) + if (RangeStatus != Sema::FRS_Success) { + if (RangeStatus == Sema::FRS_DiagnosticIssued) + SemaRef.Diag(BeginRange->getLocStart(), diag::note_in_for_range) + << ColonLoc << BEF_begin << BeginRange->getType(); return RangeStatus; + } if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc, diag::err_for_range_iter_deduction_failure)) { NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF); return Sema::FRS_DiagnosticIssued; } - *BEF = Sema::BEF_end; + *BEF = BEF_end; RangeStatus = - SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, EndVar, - Sema::BEF_end, EndNameInfo, + SemaRef.BuildForRangeBeginEndCall(ColonLoc, ColonLoc, EndNameInfo, EndMemberLookup, CandidateSet, EndRange, EndExpr); - if (RangeStatus != Sema::FRS_Success) + if (RangeStatus != Sema::FRS_Success) { + if (RangeStatus == Sema::FRS_DiagnosticIssued) + SemaRef.Diag(EndRange->getLocStart(), diag::note_in_for_range) + << ColonLoc << BEF_end << EndRange->getType(); return RangeStatus; + } if (FinishForRangeVarDecl(SemaRef, EndVar, EndExpr->get(), ColonLoc, diag::err_for_range_iter_deduction_failure)) { NoteForRangeBeginEndFunction(SemaRef, EndExpr->get(), *BEF); @@ -2086,10 +2099,9 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, if (AdjustedRange.isInvalid()) return StmtResult(); - StmtResult SR = - SemaRef.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc, - AdjustedRange.get(), RParenLoc, - Sema::BFRK_Check); + StmtResult SR = SemaRef.ActOnCXXForRangeStmt( + S, ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc, AdjustedRange.get(), + RParenLoc, Sema::BFRK_Check); if (SR.isInvalid()) return StmtResult(); } @@ -2099,8 +2111,8 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, // case there are any other (non-fatal) problems with it. SemaRef.Diag(RangeLoc, diag::err_for_range_dereference) << Range->getType() << FixItHint::CreateInsertion(RangeLoc, "*"); - return SemaRef.ActOnCXXForRangeStmt(ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc, - AdjustedRange.get(), RParenLoc, + return SemaRef.ActOnCXXForRangeStmt(S, ForLoc, CoawaitLoc, LoopVarDecl, + ColonLoc, AdjustedRange.get(), RParenLoc, Sema::BFRK_Rebuild); } @@ -2127,6 +2139,15 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, SourceLocation RParenLoc, BuildForRangeKind Kind) { + // FIXME: This should not be used during template instantiation. We should + // pick up the set of unqualified lookup results for the != and + operators + // in the initial parse. + // + // Testcase (accepts-invalid): + // template<typename T> void f() { for (auto x : T()) {} } + // namespace N { struct X { X begin(); X end(); int operator*(); }; } + // bool operator!=(N::X, N::X); void operator++(N::X); + // void g() { f<N::X>(); } Scope *S = getCurScope(); DeclStmt *RangeDS = cast<DeclStmt>(RangeDecl); @@ -2226,9 +2247,9 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, } else { OverloadCandidateSet CandidateSet(RangeLoc, OverloadCandidateSet::CSK_Normal); - Sema::BeginEndFunction BEFFailure; + BeginEndFunction BEFFailure; ForRangeStatus RangeStatus = - BuildNonArrayForRange(*this, S, BeginRangeRef.get(), + BuildNonArrayForRange(*this, BeginRangeRef.get(), EndRangeRef.get(), RangeType, BeginVar, EndVar, ColonLoc, &CandidateSet, &BeginExpr, &EndExpr, &BEFFailure); @@ -2325,7 +2346,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get()); if (!IncrExpr.isInvalid() && CoawaitLoc.isValid()) - IncrExpr = ActOnCoawaitExpr(CoawaitLoc, IncrExpr.get()); + IncrExpr = ActOnCoawaitExpr(S, CoawaitLoc, IncrExpr.get()); if (!IncrExpr.isInvalid()) IncrExpr = ActOnFinishFullExpr(IncrExpr.get()); if (IncrExpr.isInvalid()) { @@ -2364,10 +2385,10 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, if (Kind == BFRK_Check) return StmtResult(); - // FIXME: Pass in CoawaitLoc in the dependent case. return new (Context) CXXForRangeStmt( RangeDS, cast_or_null<DeclStmt>(BeginEndDecl.get()), NotEqExpr.get(), - IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, ColonLoc, RParenLoc); + IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc, + ColonLoc, RParenLoc); } /// FinishObjCForCollectionStmt - Attach the body to a objective-C foreach @@ -2925,6 +2946,9 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (CurCap->HasImplicitReturnType || NRVOCandidate) FunctionScopes.back()->Returns.push_back(Result); + if (FunctionScopes.back()->FirstReturnLoc.isInvalid()) + FunctionScopes.back()->FirstReturnLoc = ReturnLoc; + return Result; } @@ -3291,6 +3315,9 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (Result->getNRVOCandidate()) FunctionScopes.back()->Returns.push_back(Result); + if (FunctionScopes.back()->FirstReturnLoc.isInvalid()) + FunctionScopes.back()->FirstReturnLoc = ReturnLoc; + return Result; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 117ae56969d..176e57165ff 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1287,6 +1287,30 @@ public: Constraints, Clobbers, Exprs, EndLoc); } + /// \brief Build a new co_return statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + StmtResult RebuildCoreturnStmt(SourceLocation CoreturnLoc, Expr *Result) { + return getSema().BuildCoreturnStmt(CoreturnLoc, Result); + } + + /// \brief Build a new co_await expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildCoawaitExpr(SourceLocation CoawaitLoc, Expr *Result) { + return getSema().BuildCoawaitExpr(CoawaitLoc, Result); + } + + /// \brief Build a new co_yield expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildCoyieldExpr(SourceLocation CoyieldLoc, Expr *Result) { + return getSema().BuildCoyieldExpr(CoyieldLoc, Result); + } + /// \brief Build a new Objective-C \@try statement. /// /// By default, performs semantic analysis to build the new statement. @@ -1715,6 +1739,7 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc, + SourceLocation CoawaitLoc, SourceLocation ColonLoc, Stmt *Range, Stmt *BeginEnd, Expr *Cond, Expr *Inc, @@ -1737,7 +1762,6 @@ public: } } - SourceLocation CoawaitLoc; // FIXME return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, Range, BeginEnd, Cond, Inc, LoopVar, RParenLoc, @@ -6403,6 +6427,56 @@ TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) { TransformedExprs, S->getEndLoc()); } +// C++ Coroutines TS + +template<typename Derived> +StmtResult +TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { + // The coroutine body should be re-formed by the caller if necessary. + return getDerived().TransformStmt(S->getBody()); +} + +template<typename Derived> +StmtResult +TreeTransform<Derived>::TransformCoreturnStmt(CoreturnStmt *S) { + ExprResult Result = getDerived().TransformInitializer(S->getOperand(), + /*NotCopyInit*/false); + if (Result.isInvalid()) + return StmtError(); + + // Always rebuild; we don't know if this needs to be injected into a new + // context or if the promise type has changed. + return getDerived().RebuildCoreturnStmt(S->getKeywordLoc(), Result.get()); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformCoawaitExpr(CoawaitExpr *E) { + ExprResult Result = getDerived().TransformInitializer(E->getOperand(), + /*NotCopyInit*/false); + if (Result.isInvalid()) + return ExprError(); + + // Always rebuild; we don't know if this needs to be injected into a new + // context or if the promise type has changed. + return getDerived().RebuildCoawaitExpr(E->getKeywordLoc(), Result.get()); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformCoyieldExpr(CoyieldExpr *E) { + ExprResult Result = getDerived().TransformInitializer(E->getOperand(), + /*NotCopyInit*/false); + if (Result.isInvalid()) + return ExprError(); + + // Always rebuild; we don't know if this needs to be injected into a new + // context or if the promise type has changed. + return getDerived().RebuildCoyieldExpr(E->getKeywordLoc(), Result.get()); +} + +// Objective-C Statements. + template<typename Derived> StmtResult TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) { @@ -6692,6 +6766,7 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { Inc.get() != S->getInc() || LoopVar.get() != S->getLoopVarStmt()) { NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), + S->getCoawaitLoc(), S->getColonLoc(), Range.get(), BeginEnd.get(), Cond.get(), Inc.get(), LoopVar.get(), @@ -6708,6 +6783,7 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { // it now so we have a new statement to attach the body to. if (Body.get() != S->getBody() && NewStmt.get() == S) { NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), + S->getCoawaitLoc(), S->getColonLoc(), Range.get(), BeginEnd.get(), Cond.get(), Inc.get(), LoopVar.get(), |