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>; def err_implied_std_coroutine_traits_not_found : Error< - "you need to include before defining a coroutine">; + "you need to include 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< 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 /// \. ClassTemplateDecl *StdInitializerList; @@ -4255,6 +4259,8 @@ NamespaceDecl *getStdNamespace() const; NamespaceDecl *getOrCreateStdNamespace(); + NamespaceDecl *lookupStdExperimentalNamespace(); + CXXRecordDecl *getStdBadAlloc() const; EnumDecl *getStdAlignValT() const; 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: 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/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())) + Result.suppressDiagnostics(); + } + } + return StdExperimentalNamespaceCache; +} + /// \brief Retrieve the special "std" namespace, which may require us to /// implicitly define the namespace. NamespaceDecl *Sema::getOrCreateStdNamespace() { 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 }} + co_await a; // expected-error {{include }} // expected-error@-1 {{use of undeclared identifier 'a'}} } void no_coroutine_traits_bad_arg_yield() { - co_yield a; // expected-error {{include }} + co_yield a; // expected-error {{include }} // expected-error@-1 {{use of undeclared identifier 'a'}} } void no_coroutine_traits_bad_arg_return() { - co_return a; // expected-error {{include }} + co_return a; // expected-error {{include }} // expected-error@-1 {{use of undeclared identifier 'a'}} } @@ -36,45 +36,59 @@ }; void no_coroutine_traits() { - co_await a; // expected-error {{need to include }} + co_await a; // expected-error {{need to include }} } namespace std { - template struct coroutine_traits; // expected-note {{declared here}} -}; +namespace experimental { +template +struct coroutine_traits; // expected-note {{declared here}} +} +} template struct coro {}; -template -struct std::coroutine_traits, Ps...> { +template +struct std::experimental::coroutine_traits, Ps...> { using promise_type = Promise; }; void no_specialization() { - co_await a; // expected-error {{implicit instantiation of undefined template 'std::coroutine_traits'}} + co_await a; // expected-error {{implicit instantiation of undefined template 'std::experimental::coroutine_traits'}} } -template struct std::coroutine_traits {}; +template +struct std::experimental::coroutine_traits {}; int no_promise_type() { - co_await a; // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits' has no member named 'promise_type'}} + co_await a; // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits' has no member named 'promise_type'}} } -template<> struct std::coroutine_traits { typedef int promise_type; }; +template <> +struct std::experimental::coroutine_traits { typedef int promise_type; }; double bad_promise_type(double) { - co_await a; // expected-error {{this function cannot be a coroutine: 'std::coroutine_traits::promise_type' (aka 'int') is not a class}} + co_await a; // expected-error {{this function cannot be a coroutine: 'experimental::coroutine_traits::promise_type' (aka 'int') is not a class}} } -template<> struct std::coroutine_traits { +template <> +struct std::experimental::coroutine_traits { struct promise_type {}; }; double bad_promise_type_2(int) { - co_yield 0; // expected-error {{no member named 'yield_value' in 'std::coroutine_traits::promise_type'}} + co_yield 0; // expected-error {{no member named 'yield_value' in 'std::experimental::coroutine_traits::promise_type'}} } struct promise; // expected-note 2{{forward declaration}} -template struct std::coroutine_traits { using promise_type = promise; }; +template +struct std::experimental::coroutine_traits { using promise_type = promise; }; + +namespace std { +namespace experimental { +template +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 { +template <> +struct std::experimental::coroutine_traits { struct promise_type { // FIXME: add an await_transform overload for functions awaitable yield_value(int()); @@ -285,7 +300,7 @@ } -template<> struct std::coroutine_traits +template<> struct std::experimental::coroutine_traits { using promise_type = promise; }; int main(int, const char**) { // expected-error {{'main' cannot be a coroutine}}