Skip to content

Commit 508717f

Browse files
committed
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).
1 parent d9cf0db commit 508717f

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

clang/lib/Parse/Parser.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2020,6 +2020,17 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(
20202020
CXXScopeSpec &SS, bool IsNewScope,
20212021
ImplicitTypenameContext AllowImplicitTypename) {
20222022
if (Tok.is(tok::identifier)) {
2023+
// When we have a qualified type name (io_context::impl_type) at file scope,
2024+
// suppress access checks because this might be the return type of an
2025+
// out-of-line member function definition. In such cases, the name should be
2026+
// looked up as if we were inside the class scope.
2027+
bool SuppressAccess = SS.isNotEmpty() && getCurScope() &&
2028+
!getCurScope()->isClassScope() &&
2029+
!getCurScope()->isFunctionScope();
2030+
std::optional<SuppressAccessChecks> SAC;
2031+
if (SuppressAccess)
2032+
SAC.emplace(*this, true);
2033+
20232034
// Determine whether the identifier is a type name.
20242035
if (ParsedType Ty = Actions.getTypeName(
20252036
*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: cat %s | clang-repl | FileCheck %s
2+
3+
extern "C" int printf(const char*, ...);
4+
5+
struct scheduler { };
6+
class io_context { using impl_type = scheduler; public: impl_type *get_impl(); };
7+
io_context::impl_type *io_context::get_impl() { return nullptr; }
8+
printf("Private type alias: passed\n");
9+
// CHECK: Private type alias: passed
10+
11+
class Container { struct Node { int data; }; public: Node* create(); };
12+
Container::Node* Container::create() { return new Node{456}; }
13+
printf("Private nested struct: %d\n", Container().create()->data);
14+
// CHECK: Private nested struct: 456
15+
16+
class Status { enum Code { OK = 0 }; public: Code get(); };
17+
Status::Code Status::get() { return OK; }
18+
printf("Private enum: %d\n", Status().get());
19+
// CHECK: Private enum: 0
20+
21+
template<typename T> class Handler { using ptr = T*; public: ptr get(); };
22+
template<typename T> typename Handler<T>::ptr Handler<T>::get() { return nullptr; }
23+
printf("Template with private type: passed\n");
24+
// CHECK: Template with private type: passed
25+
26+
namespace ns { class C { using val_t = double; public: val_t compute(); }; }
27+
ns::C::val_t ns::C::compute() { return 3.14; }
28+
printf("Namespace qualified: %.2f\n", ns::C().compute());
29+
// CHECK: Namespace qualified: 3.14
30+
31+
%quit

0 commit comments

Comments
 (0)