GorNishanov updated this revision to Diff 73378. GorNishanov marked an inline comment as done. GorNishanov added a comment.
Implemented review feedback. Landing is imminent. https://reviews.llvm.org/D25068 Files: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/Sema/Sema.cpp lib/Sema/SemaCoroutine.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/coroutines.cpp
Index: test/SemaCXX/coroutines.cpp =================================================================== --- test/SemaCXX/coroutines.cpp +++ test/SemaCXX/coroutines.cpp @@ -1,18 +1,18 @@ // RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -verify %s void no_coroutine_traits_bad_arg_await() { - co_await a; // expected-error {{include <coroutine>}} + co_await a; // expected-error {{include <experimental/coroutine>}} // expected-error@-1 {{use of undeclared identifier 'a'}} } void no_coroutine_traits_bad_arg_yield() { - co_yield a; // expected-error {{include <coroutine>}} + co_yield a; // expected-error {{include <experimental/coroutine>}} // expected-error@-1 {{use of undeclared identifier 'a'}} } void no_coroutine_traits_bad_arg_return() { - co_return a; // expected-error {{include <coroutine>}} + co_return a; // expected-error {{include <experimental/coroutine>}} // expected-error@-1 {{use of undeclared identifier 'a'}} } @@ -36,45 +36,59 @@ }; void no_coroutine_traits() { - co_await a; // expected-error {{need to include <coroutine>}} + co_await a; // expected-error {{need to include <experimental/coroutine>}} } namespace std { - template<typename ...T> struct coroutine_traits; // expected-note {{declared here}} -}; +namespace experimental { +template <typename... T> +struct coroutine_traits; // expected-note {{declared here}} +} +} template<typename Promise> struct coro {}; -template<typename Promise, typename... Ps> -struct std::coroutine_traits<coro<Promise>, Ps...> { +template <typename Promise, typename... Ps> +struct std::experimental::coroutine_traits<coro<Promise>, Ps...> { using promise_type = Promise; }; void no_specialization() { - co_await a; // expected-error {{implicit instantiation of undefined template 'std::coroutine_traits<void>'}} + co_await a; // expected-error {{implicit instantiation of undefined template 'std::experimental::coroutine_traits<void>'}} } -template<typename ...T> struct std::coroutine_traits<int, T...> {}; +template <typename... T> +struct std::experimental::coroutine_traits<int, T...> {}; int no_promise_type() { - co_await a; // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<int>' has no member named 'promise_type'}} + co_await a; // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<int>' has no member named 'promise_type'}} } -template<> struct std::coroutine_traits<double, double> { typedef int promise_type; }; +template <> +struct std::experimental::coroutine_traits<double, double> { typedef int promise_type; }; double bad_promise_type(double) { - co_await a; // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}} + co_await a; // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits<double, double>::promise_type' (aka 'int') is not a class}} } -template<> struct std::coroutine_traits<double, int> { +template <> +struct std::experimental::coroutine_traits<double, int> { struct promise_type {}; }; double bad_promise_type_2(int) { - co_yield 0; // expected-error {{no member named 'yield_value' in 'std::coroutine_traits<double, int>::promise_type'}} + co_yield 0; // expected-error {{no member named 'yield_value' in 'std::experimental::coroutine_traits<double, int>::promise_type'}} } struct promise; // expected-note 2{{forward declaration}} -template<typename ...T> struct std::coroutine_traits<void, T...> { using promise_type = promise; }; +template <typename... T> +struct std::experimental::coroutine_traits<void, T...> { using promise_type = promise; }; + +namespace std { +namespace experimental { +template <typename Promise = void> +struct coroutine_handle; +} +} - // FIXME: This diagnostic is terrible. +// FIXME: This diagnostic is terrible. void undefined_promise() { // expected-error {{variable has incomplete type 'promise_type'}} // FIXME: This diagnostic doesn't make any sense. // expected-error@-2 {{incomplete definition of type 'promise'}} @@ -200,7 +214,8 @@ } struct yield_fn_tag {}; -template<> struct std::coroutine_traits<void, yield_fn_tag> { +template <> +struct std::experimental::coroutine_traits<void, yield_fn_tag> { struct promise_type { // FIXME: add an await_transform overload for functions awaitable yield_value(int()); @@ -285,7 +300,7 @@ } -template<> struct std::coroutine_traits<int, int, const char**> +template<> struct std::experimental::coroutine_traits<int, int, const char**> { using promise_type = promise; }; int main(int, const char**) { // expected-error {{'main' cannot be a coroutine}} Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -8275,6 +8275,20 @@ StdNamespace.get(Context.getExternalSource())); } +NamespaceDecl *Sema::lookupStdExperimentalNamespace() { + if (!StdExperimentalNamespaceCache) { + if (auto Std = getStdNamespace()) { + LookupResult Result(*this, &PP.getIdentifierTable().get("experimental"), + SourceLocation(), LookupNamespaceName); + if (!LookupQualifiedName(Result, Std) || + !(StdExperimentalNamespaceCache = + Result.getAsSingle<NamespaceDecl>())) + Result.suppressDiagnostics(); + } + } + return StdExperimentalNamespaceCache; +} + /// \brief Retrieve the special "std" namespace, which may require us to /// implicitly define the namespace. NamespaceDecl *Sema::getOrCreateStdNamespace() { Index: lib/Sema/SemaCoroutine.cpp =================================================================== --- lib/Sema/SemaCoroutine.cpp +++ lib/Sema/SemaCoroutine.cpp @@ -26,15 +26,15 @@ 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) { + NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace(); + if (!StdExp) { 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)) { + if (!S.LookupQualifiedName(Result, StdExp)) { S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found); return QualType(); } @@ -86,7 +86,7 @@ QualType PromiseType = S.Context.getTypeDeclType(Promise); if (!PromiseType->getAsCXXRecordDecl()) { // Use the fully-qualified name of the type. - auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, Std); + auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, StdExp); NNS = NestedNameSpecifier::Create(S.Context, NNS, false, CoroTrait.getTypePtr()); PromiseType = S.Context.getElaboratedType(ETK_None, NNS, PromiseType); @@ -345,6 +345,7 @@ } return BuildCoreturnStmt(Loc, E); } + StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) { auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return"); if (!Coroutine) Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -88,8 +88,8 @@ VisContext(nullptr), IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr), - LateTemplateParserCleanup(nullptr), - OpaqueParser(nullptr), IdResolver(pp), StdInitializerList(nullptr), + LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp), + StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr), CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), NSNumberDecl(nullptr), NSValueDecl(nullptr), NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr), Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -725,6 +725,10 @@ /// standard library. LazyDeclPtr StdAlignValT; + /// \brief The C++ "std::experimental" namespace, where the experimental parts + /// of the standard library resides. + NamespaceDecl *StdExperimentalNamespaceCache; + /// \brief The C++ "std::initializer_list" template, which is defined in /// \<initializer_list>. ClassTemplateDecl *StdInitializerList; @@ -4255,6 +4259,8 @@ NamespaceDecl *getStdNamespace() const; NamespaceDecl *getOrCreateStdNamespace(); + NamespaceDecl *lookupStdExperimentalNamespace(); + CXXRecordDecl *getStdBadAlloc() const; EnumDecl *getStdAlignValT() const; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -8572,9 +8572,9 @@ "that uses neither 'co_await' nor 'co_yield'">, InGroup<DiagGroup<"coreturn-without-coawait">>; def err_implied_std_coroutine_traits_not_found : Error< - "you need to include <coroutine> before defining a coroutine">; + "you need to include <experimental/coroutine> before defining a coroutine">; def err_malformed_std_coroutine_traits : Error< - "'std::coroutine_traits' must be a class template">; + "'std::experimental::coroutine_traits' must be a class template">; def err_implied_std_coroutine_traits_promise_type_not_found : Error< "this function cannot be a coroutine: %q0 has no member named 'promise_type'">; def err_implied_std_coroutine_traits_promise_type_not_class : Error<
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits