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

Reply via email to