https://github.com/pfeodrippe updated https://github.com/llvm/llvm-project/pull/169272
>From ede7a1e23ef66fce96b0b69ef7499ba034c17acd Mon Sep 17 00:00:00 2001 From: Paulo Feodrippe <[email protected]> Date: Sun, 23 Nov 2025 22:34:43 -0500 Subject: [PATCH] clang][Parser] Allow private type aliases in out-of-line member function return types When parsing qualified type names (e.g., `io_context::impl_type`) at file scope in clang-repl, suppress access checks during type annotation. This allows private member type aliases to be used in return types of out-of-line member function definitions, matching the C++ standard's scoping rules for such declarations. Fixes: Parsing errors in clang-repl when including headers with out-of-line member functions that return private nested types (e.g., ASIO's io_context::impl_type). --- clang/lib/Parse/Parser.cpp | 11 +++++++ .../Interpreter/private-member-access.cpp | 31 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 clang/test/Interpreter/private-member-access.cpp diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index a6fc676f23a51..3e2dd7b9674f2 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2020,6 +2020,17 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec( CXXScopeSpec &SS, bool IsNewScope, ImplicitTypenameContext AllowImplicitTypename) { if (Tok.is(tok::identifier)) { + // When we have a qualified type name (io_context::impl_type) at file scope, + // suppress access checks because this might be the return type of an + // out-of-line member function definition. In such cases, the name should be + // looked up as if we were inside the class scope. + bool SuppressAccess = SS.isNotEmpty() && getCurScope() && + !getCurScope()->isClassScope() && + !getCurScope()->isFunctionScope(); + std::optional<SuppressAccessChecks> SAC; + if (SuppressAccess) + SAC.emplace(*this, true); + // Determine whether the identifier is a type name. if (ParsedType Ty = Actions.getTypeName( *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS, diff --git a/clang/test/Interpreter/private-member-access.cpp b/clang/test/Interpreter/private-member-access.cpp new file mode 100644 index 0000000000000..0d02f09332612 --- /dev/null +++ b/clang/test/Interpreter/private-member-access.cpp @@ -0,0 +1,31 @@ +// RUN: cat %s | clang-repl | FileCheck %s + +extern "C" int printf(const char*, ...); + +struct scheduler { }; +class io_context { using impl_type = scheduler; public: impl_type *get_impl(); }; +io_context::impl_type *io_context::get_impl() { return nullptr; } +printf("Private type alias: passed\n"); +// CHECK: Private type alias: passed + +class Container { struct Node { int data; }; public: Node* create(); }; +Container::Node* Container::create() { return new Node{456}; } +printf("Private nested struct: %d\n", Container().create()->data); +// CHECK: Private nested struct: 456 + +class Status { enum Code { OK = 0 }; public: Code get(); }; +Status::Code Status::get() { return OK; } +printf("Private enum: %d\n", Status().get()); +// CHECK: Private enum: 0 + +template<typename T> class Handler { using ptr = T*; public: ptr get(); }; +template<typename T> typename Handler<T>::ptr Handler<T>::get() { return nullptr; } +printf("Template with private type: passed\n"); +// CHECK: Template with private type: passed + +namespace ns { class C { using val_t = double; public: val_t compute(); }; } +ns::C::val_t ns::C::compute() { return 3.14; } +printf("Namespace qualified: %.2f\n", ns::C().compute()); +// CHECK: Namespace qualified: 3.14 + +%quit _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
