EricWF updated this revision to Diff 101854.
EricWF added a comment.
- Fix clang-format nonsense in tests.
https://reviews.llvm.org/D34021
Files:
include/clang/Sema/Sema.h
lib/Sema/SemaCoroutine.cpp
lib/Sema/SemaStmt.cpp
test/SemaCXX/coawait_range_for.cpp
Index: test/SemaCXX/coawait_range_for.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/coawait_range_for.cpp
@@ -0,0 +1,187 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts \
+// RUN: -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify \
+// RUN: -fblocks
+#include "Inputs/std-coroutine.h"
+
+using namespace std::experimental;
+
+template <bool, class = void>
+struct EnableIf {};
+template <class T>
+struct EnableIf<true, T> { using type = T; };
+template <bool P, class T = void>
+using EnableIfT = typename EnableIf<P, T>::type;
+
+template <class Begin>
+struct Awaiter {
+ Awaiter(Begin b);
+ bool await_ready();
+ void await_suspend(coroutine_handle<>);
+ Begin await_resume();
+};
+
+template <class Iter>
+struct BeginTag {
+ BeginTag() = delete;
+};
+
+template <class Iter>
+struct IncTag {
+ IncTag() = delete;
+};
+
+template <class Iter, bool Delete = false>
+struct CoawaitTag {
+ CoawaitTag() = delete;
+};
+
+template <class T>
+struct MyIter {
+ using value_type = T;
+ using reference = T &;
+ using pointer = T *;
+
+ IncTag<MyIter> operator++();
+ reference operator*();
+ pointer operator->();
+};
+template <class T>
+bool operator==(MyIter<T>, MyIter<T>);
+template <class T>
+bool operator!=(MyIter<T>, MyIter<T>);
+
+template <class T>
+struct MyRange {
+ BeginTag<MyIter<T>> begin();
+ MyIter<T> end();
+};
+
+struct MyForLoopArrayAwaiter {
+ struct promise_type {
+ MyForLoopArrayAwaiter get_return_object() { return {}; }
+ void return_void();
+ void unhandled_exception();
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+ template <class T>
+ Awaiter<T *> await_transform(T *) = delete; // expected-note {{explicitly deleted}}
+ };
+};
+MyForLoopArrayAwaiter g() {
+ int arr[10] = {0};
+ for co_await(auto i : arr)
+ // expected-error@-1 {{call to deleted member function 'await_transform'}}
+ // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
+ {
+ }
+}
+
+struct ForLoopAwaiterBadBeginTransform {
+ struct promise_type {
+ ForLoopAwaiterBadBeginTransform get_return_object();
+ void return_void();
+ void unhandled_exception();
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+
+ template <class T>
+ Awaiter<T> await_transform(BeginTag<T>) = delete; // expected-note 1+ {{explicitly deleted}}
+
+ template <class T>
+ CoawaitTag<T> await_transform(IncTag<T>); // expected-note 1+ {{candidate}}
+ };
+};
+ForLoopAwaiterBadBeginTransform bad_begin() {
+ MyRange<int> R;
+ for
+ co_await(auto i
+ : R) {
+ // expected-error@-1 {{call to deleted member function 'await_transform'}}
+ // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
+ }
+}
+template <class Dummy>
+ForLoopAwaiterBadBeginTransform bad_begin_template(Dummy) {
+ MyRange<Dummy> R;
+ for
+ co_await(auto i
+ : R) {
+ // expected-error@-1 {{call to deleted member function 'await_transform'}}
+ // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
+ }
+}
+template ForLoopAwaiterBadBeginTransform bad_begin_template(int); // expected-note {{requested here}}
+
+template <class Iter>
+Awaiter<Iter> operator co_await(CoawaitTag<Iter, true>) = delete;
+// expected-note@-1 1+ {{explicitly deleted}}
+
+struct ForLoopAwaiterBadIncTransform {
+ struct promise_type {
+ ForLoopAwaiterBadIncTransform get_return_object();
+ void return_void();
+ void unhandled_exception();
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+
+ template <class T>
+ Awaiter<T> await_transform(BeginTag<T> e);
+
+ template <class T>
+ CoawaitTag<T, true> await_transform(IncTag<T>);
+ };
+};
+ForLoopAwaiterBadIncTransform bad_inc_transform() {
+ MyRange<float> R;
+ for co_await(auto i : R) {
+ // expected-error@-1 {{overload resolution selected deleted operator 'co_await'}}
+ // expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'MyRange<float>'}}
+ ((void)i);
+ }
+}
+
+template <class Dummy>
+ForLoopAwaiterBadIncTransform bad_inc_transform_template(Dummy) {
+ MyRange<Dummy> R;
+ for co_await(auto i : R) {
+ // expected-error@-1 {{overload resolution selected deleted operator 'co_await'}}
+ // expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'MyRange<long>'}}
+ ((void)i);
+ }
+}
+template ForLoopAwaiterBadIncTransform bad_inc_transform_template(long); // expected-note {{requested here}}
+
+// Ensure we mark and check the function as a coroutine even if it's
+// never instantiated.
+template <class T>
+constexpr void never_instant(T) {
+ for co_await(auto i : foo(T{})) {}
+ // expected-error@-1 {{'co_await' cannot be used in a constexpr function}}
+}
+
+struct ForLoopAwaiterCoawaitLookup {
+ struct promise_type {
+ ForLoopAwaiterCoawaitLookup get_return_object();
+ void return_void();
+ void unhandled_exception();
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+ template <class T>
+ CoawaitTag<T, false> await_transform(BeginTag<T> e);
+ template <class T>
+ Awaiter<T> await_transform(IncTag<T>);
+ };
+};
+template <class T>
+ForLoopAwaiterCoawaitLookup test_coawait_lookup(T) {
+ MyRange<T> R;
+ for co_await(auto i : R) {}
+ // expected-error@-1 {{no member named 'await_ready' in 'CoawaitTag<MyIter<int>, false>'}}
+}
+template ForLoopAwaiterCoawaitLookup test_coawait_lookup(int); // expected-note {{requested here}}
+
+// FIXME: This test should fail as well since the newly declared operator co_await
+// should not be found by lookup.
+template <class Iter>
+Awaiter<Iter> operator co_await(CoawaitTag<Iter, false>);
+template ForLoopAwaiterCoawaitLookup test_coawait_lookup(long);
Index: lib/Sema/SemaStmt.cpp
===================================================================
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -1989,11 +1989,11 @@
return StmtError();
}
- // Coroutines: 'for co_await' implicitly co_awaits its range.
- if (CoawaitLoc.isValid()) {
- ExprResult Coawait = ActOnCoawaitExpr(S, CoawaitLoc, Range);
- if (Coawait.isInvalid()) return StmtError();
- Range = Coawait.get();
+ // Build the coroutine state immediately and not later during template
+ // instantiation
+ if (!CoawaitLoc.isInvalid()) {
+ if (!ActOnCoroutineBodyStart(S, CoawaitLoc, "co_await"))
+ return StmtError();
}
// Build auto && __range = range-init
@@ -2031,16 +2031,12 @@
/// 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,
- Expr *BeginRange, Expr *EndRange,
- QualType RangeType,
- VarDecl *BeginVar,
- VarDecl *EndVar,
- SourceLocation ColonLoc,
- OverloadCandidateSet *CandidateSet,
- ExprResult *BeginExpr,
- ExprResult *EndExpr,
- BeginEndFunction *BEF) {
+static Sema::ForRangeStatus
+BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange,
+ QualType RangeType, VarDecl *BeginVar, VarDecl *EndVar,
+ SourceLocation ColonLoc, SourceLocation CoawaitLoc,
+ OverloadCandidateSet *CandidateSet, ExprResult *BeginExpr,
+ ExprResult *EndExpr, BeginEndFunction *BEF) {
DeclarationNameInfo BeginNameInfo(
&SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc);
DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"),
@@ -2087,6 +2083,15 @@
<< ColonLoc << BEF_begin << BeginRange->getType();
return RangeStatus;
}
+ if (!CoawaitLoc.isInvalid()) {
+ // FIXME: getCurScope() should not be used during template instantiation.
+ // We should pick up the set of unqualified lookup results for operator
+ // co_await during the initial parse.
+ *BeginExpr = SemaRef.ActOnCoawaitExpr(SemaRef.getCurScope(), ColonLoc,
+ BeginExpr->get());
+ if (BeginExpr->isInvalid())
+ return Sema::FRS_DiagnosticIssued;
+ }
if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc,
diag::err_for_range_iter_deduction_failure)) {
NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF);
@@ -2249,6 +2254,11 @@
// begin-expr is __range.
BeginExpr = BeginRangeRef;
+ if (!CoawaitLoc.isInvalid()) {
+ BeginExpr = ActOnCoawaitExpr(S, ColonLoc, BeginExpr.get());
+ if (BeginExpr.isInvalid())
+ return StmtError();
+ }
if (FinishForRangeVarDecl(*this, BeginVar, BeginRangeRef.get(), ColonLoc,
diag::err_for_range_iter_deduction_failure)) {
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
@@ -2331,11 +2341,10 @@
OverloadCandidateSet CandidateSet(RangeLoc,
OverloadCandidateSet::CSK_Normal);
BeginEndFunction BEFFailure;
- ForRangeStatus RangeStatus =
- BuildNonArrayForRange(*this, BeginRangeRef.get(),
- EndRangeRef.get(), RangeType,
- BeginVar, EndVar, ColonLoc, &CandidateSet,
- &BeginExpr, &EndExpr, &BEFFailure);
+ ForRangeStatus RangeStatus = BuildNonArrayForRange(
+ *this, BeginRangeRef.get(), EndRangeRef.get(), RangeType, BeginVar,
+ EndVar, ColonLoc, CoawaitLoc, &CandidateSet, &BeginExpr, &EndExpr,
+ &BEFFailure);
if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction &&
BEFFailure == BEF_begin) {
@@ -2432,6 +2441,9 @@
IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get());
if (!IncrExpr.isInvalid() && CoawaitLoc.isValid())
+ // FIXME: getCurScope() should not be used during template instantiation.
+ // We should pick up the set of unqualified lookup results for operator
+ // co_await during the initial parse.
IncrExpr = ActOnCoawaitExpr(S, CoawaitLoc, IncrExpr.get());
if (!IncrExpr.isInvalid())
IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
Index: lib/Sema/SemaCoroutine.cpp
===================================================================
--- lib/Sema/SemaCoroutine.cpp
+++ lib/Sema/SemaCoroutine.cpp
@@ -470,11 +470,11 @@
return ScopeInfo;
}
-static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc,
- StringRef Keyword) {
- if (!checkCoroutineContext(S, KWLoc, Keyword))
+bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
+ StringRef Keyword) {
+ if (!checkCoroutineContext(*this, KWLoc, Keyword))
return false;
- auto *ScopeInfo = S.getCurFunction();
+ auto *ScopeInfo = getCurFunction();
assert(ScopeInfo->CoroutinePromise);
// If we have existing coroutine statements then we have already built
@@ -484,24 +484,24 @@
ScopeInfo->setNeedsCoroutineSuspends(false);
- auto *Fn = cast<FunctionDecl>(S.CurContext);
+ auto *Fn = cast<FunctionDecl>(CurContext);
SourceLocation Loc = Fn->getLocation();
// Build the initial suspend point
auto buildSuspends = [&](StringRef Name) mutable -> StmtResult {
ExprResult Suspend =
- buildPromiseCall(S, ScopeInfo->CoroutinePromise, Loc, Name, None);
+ buildPromiseCall(*this, ScopeInfo->CoroutinePromise, Loc, Name, None);
if (Suspend.isInvalid())
return StmtError();
- Suspend = buildOperatorCoawaitCall(S, SC, Loc, Suspend.get());
+ Suspend = buildOperatorCoawaitCall(*this, SC, Loc, Suspend.get());
if (Suspend.isInvalid())
return StmtError();
- Suspend = S.BuildResolvedCoawaitExpr(Loc, Suspend.get(),
- /*IsImplicit*/ true);
- Suspend = S.ActOnFinishFullExpr(Suspend.get());
+ Suspend = BuildResolvedCoawaitExpr(Loc, Suspend.get(),
+ /*IsImplicit*/ true);
+ Suspend = ActOnFinishFullExpr(Suspend.get());
if (Suspend.isInvalid()) {
- S.Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required)
+ Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required)
<< ((Name == "initial_suspend") ? 0 : 1);
- S.Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword;
+ Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword;
return StmtError();
}
return cast<Stmt>(Suspend.get());
@@ -521,7 +521,7 @@
}
ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
- if (!actOnCoroutineBodyStart(*this, S, Loc, "co_await")) {
+ if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) {
CorrectDelayedTyposInExpr(E);
return ExprError();
}
@@ -613,7 +613,7 @@
}
ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
- if (!actOnCoroutineBodyStart(*this, S, Loc, "co_yield")) {
+ if (!ActOnCoroutineBodyStart(S, Loc, "co_yield")) {
CorrectDelayedTyposInExpr(E);
return ExprError();
}
@@ -665,7 +665,7 @@
}
StmtResult Sema::ActOnCoreturnStmt(Scope *S, SourceLocation Loc, Expr *E) {
- if (!actOnCoroutineBodyStart(*this, S, Loc, "co_return")) {
+ if (!ActOnCoroutineBodyStart(S, Loc, "co_return")) {
CorrectDelayedTyposInExpr(E);
return StmtError();
}
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -8364,6 +8364,8 @@
//===--------------------------------------------------------------------===//
// C++ Coroutines TS
//
+ bool ActOnCoroutineBodyStart(Scope *S, SourceLocation KwLoc,
+ StringRef Keyword);
ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E);
ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E);
StmtResult ActOnCoreturnStmt(Scope *S, SourceLocation KwLoc, Expr *E);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits