GorNishanov created this revision. GorNishanov added reviewers: EricWF, rsmith, cfe-commits. Herald added a subscriber: mehdi_amini. | View Revision
Look for coroutine_traits and friends in std::experimental namespace.
Patch (mostly) by EricWF.
Files:
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaCoroutine.cpp
lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/coroutines.cpp
include/clang/Sema/Sema.h
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 -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,43 +36,48 @@ }; 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 { +namespace std { 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...> { +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. void undefined_promise() { // expected-error {{variable has incomplete type 'promise_type'}} @@ -200,7 +205,7 @@ } 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()); Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -8111,6 +8111,7 @@ bool IsInline = InlineLoc.isValid(); bool IsInvalid = false; bool IsStd = false; + bool IsStdExperimental = false; bool AddToKnown = false; Scope *DeclRegionScope = NamespcScope->getParent(); @@ -8152,6 +8153,11 @@ PrevNS = getStdNamespace(); IsStd = true; AddToKnown = !IsInline; + } else if (II->isStr("experimental") && + CurContext->getRedeclContext()->isStdNamespace()) { + PrevNS = getStdExperimentalNamespace(); + IsStdExperimental = true; + AddToKnown = !IsInline; } else { // We've seen this namespace for the first time. AddToKnown = !IsInline; @@ -8186,6 +8192,8 @@ if (IsStd) StdNamespace = Namespc; + if (IsStdExperimental) + StdExperimentalNamespace = Namespc; if (AddToKnown) KnownNamespaces[Namespc] = false; @@ -8275,6 +8283,12 @@ StdNamespace.get(Context.getExternalSource())); } + +NamespaceDecl *Sema::getStdExperimentalNamespace() const { + return cast_or_null<NamespaceDecl>( + StdExperimentalNamespace.get(Context.getExternalSource())); +} + /// \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.getStdExperimentalNamespace(); + 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); Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -717,6 +717,10 @@ /// \brief The C++ "std" namespace, where the standard library resides. LazyDeclPtr StdNamespace; + /// \brief The C++ "std::experimental" namespace, where the experimental parts + /// of the standard library resides. + LazyDeclPtr StdExperimentalNamespace; + /// \brief The C++ "std::bad_alloc" class, which is defined by the C++ /// standard library. LazyDeclPtr StdBadAlloc; @@ -4240,6 +4244,8 @@ NamespaceDecl *getStdNamespace() const; NamespaceDecl *getOrCreateStdNamespace(); + NamespaceDecl *getStdExperimentalNamespace() const; + CXXRecordDecl *getStdBadAlloc() const; EnumDecl *getStdAlignValT() const; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -8569,9 +8569,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