Skip to content

Commit e1ca2f5

Browse files
committed
[clang][Parser] Allow private type aliases in out-of-line member function return types
Bug: In clang-repl (incremental parsing mode), out-of-line member function definitions that use private/protected type aliases in their return type incorrectly fail with access errors (e.g., io_context::impl_type *io_context::foo() errors with "'impl_type' is a private member of 'io_context'"). This happens because the disambiguation logic in isCXXDeclarationStatement calls isCXXSimpleDeclaration, which triggers access checking before the parser establishes the correct declaration context. Fix: Extend the heuristic in ParseTentative.cpp that skips isCXXSimpleDeclaration to also recognize pointer/reference patterns (A::B *id, A::B &id, A::B &&id, A::B **id) as likely declarations, avoiding the premature access check.
1 parent 6f7ea34 commit e1ca2f5

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed

clang/lib/Parse/ParseTentative.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,26 @@ bool Parser::isCXXDeclarationStatement(
6161
// token is also an identifier and assume a declaration.
6262
// We cannot check if the scopes match because the declarations could
6363
// involve namespaces and friend declarations.
64-
if (NextToken().is(tok::identifier))
64+
//
65+
// Also handle cases like "A::B *foo" or "A::B &foo" where the type
66+
// is followed by ptr/ref declarator operators. These patterns are
67+
// very likely to be declarations (e.g., out-of-line member function
68+
// definitions with pointer/reference return types).
69+
Token Next = NextToken();
70+
if (Next.is(tok::identifier))
6571
return true;
72+
// Check for pointer/reference patterns: A::B *id, A::B &id, A::B &&id
73+
// Also handles multiple indirections like A::B **id
74+
if (Next.isOneOf(tok::star, tok::amp, tok::ampamp)) {
75+
// Look ahead to see if there's an identifier after ptr/ref ops
76+
RevertingTentativeParsingAction PA(*this);
77+
ConsumeToken(); // consume the identifier (type name)
78+
// Skip all consecutive *, &, && tokens (for cases like A::B **)
79+
while (Tok.isOneOf(tok::star, tok::amp, tok::ampamp))
80+
ConsumeToken();
81+
if (Tok.is(tok::identifier))
82+
return true;
83+
}
6684
}
6785
break;
6886
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: cat %s | clang-repl | FileCheck %s
2+
3+
extern "C" int printf(const char*, ...);
4+
5+
// Test 1: Pointer to private type alias (the original bug report)
6+
class io_context { using impl_type = int; public: impl_type* get(); };
7+
io_context::impl_type* io_context::get() { return nullptr; }
8+
printf("Pointer to private type: %s\n", io_context().get() == nullptr ? "passed" : "failed");
9+
// CHECK: Pointer to private type: passed
10+
11+
// Test 2: Reference to private type
12+
class RefReturn { using ref_t = int; ref_t value = 42; public: ref_t& getRef(); };
13+
RefReturn::ref_t& RefReturn::getRef() { return value; }
14+
printf("Reference to private type: %d\n", RefReturn().getRef());
15+
// CHECK: Reference to private type: 42
16+
17+
// Test 3: Double pointer to private type
18+
class PtrPtr { using inner_t = int; public: inner_t** get(); };
19+
PtrPtr::inner_t** PtrPtr::get() { static int* p = nullptr; return &p; }
20+
printf("Double pointer to private type: %s\n", PtrPtr().get() != nullptr ? "passed" : "failed");
21+
// CHECK: Double pointer to private type: passed
22+
23+
// Test 4: Const reference to private type
24+
class ConstRef { using data_t = int; data_t val = 100; public: const data_t& get(); };
25+
const ConstRef::data_t& ConstRef::get() { return val; }
26+
printf("Const reference to private type: %d\n", ConstRef().get());
27+
// CHECK: Const reference to private type: 100
28+
29+
// Test 5: Pointer to private nested struct
30+
class Container { struct Node { int x; }; public: Node* create(); };
31+
Container::Node* Container::create() { return new Node{789}; }
32+
printf("Pointer to private nested struct: %d\n", Container().create()->x);
33+
// CHECK: Pointer to private nested struct: 789
34+
35+
%quit

0 commit comments

Comments
 (0)