diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 82f2294ff5bb7..ac16066460e13 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -61,8 +61,26 @@ bool Parser::isCXXDeclarationStatement( // token is also an identifier and assume a declaration. // We cannot check if the scopes match because the declarations could // involve namespaces and friend declarations. - if (NextToken().is(tok::identifier)) + // + // Also handle cases like "A::B *foo" or "A::B &foo" where the type + // is followed by ptr/ref declarator operators. These patterns are + // very likely to be declarations (e.g., out-of-line member function + // definitions with pointer/reference return types). + Token Next = NextToken(); + if (Next.is(tok::identifier)) return true; + // Check for pointer/reference patterns: A::B *id, A::B &id, A::B &&id + // Also handles multiple indirections like A::B **id + if (Next.isOneOf(tok::star, tok::amp, tok::ampamp)) { + // Look ahead to see if there's an identifier after ptr/ref ops + RevertingTentativeParsingAction PA(*this); + ConsumeToken(); // consume the identifier (type name) + // Skip all consecutive *, &, && tokens (for cases like A::B **) + while (Tok.isOneOf(tok::star, tok::amp, tok::ampamp)) + ConsumeToken(); + if (Tok.is(tok::identifier)) + return true; + } } break; } diff --git a/clang/test/Interpreter/private-member-access.cpp b/clang/test/Interpreter/private-member-access.cpp new file mode 100644 index 0000000000000..101e2beed4889 --- /dev/null +++ b/clang/test/Interpreter/private-member-access.cpp @@ -0,0 +1,35 @@ +// RUN: cat %s | clang-repl | FileCheck %s + +extern "C" int printf(const char*, ...); + +// Test 1: Pointer to private type alias (the original bug report) +class io_context { using impl_type = int; public: impl_type* get(); }; +io_context::impl_type* io_context::get() { return nullptr; } +printf("Pointer to private type: %s\n", io_context().get() == nullptr ? "passed" : "failed"); +// CHECK: Pointer to private type: passed + +// Test 2: Reference to private type +class RefReturn { using ref_t = int; ref_t value = 42; public: ref_t& getRef(); }; +RefReturn::ref_t& RefReturn::getRef() { return value; } +printf("Reference to private type: %d\n", RefReturn().getRef()); +// CHECK: Reference to private type: 42 + +// Test 3: Double pointer to private type +class PtrPtr { using inner_t = int; public: inner_t** get(); }; +PtrPtr::inner_t** PtrPtr::get() { static int* p = nullptr; return &p; } +printf("Double pointer to private type: %s\n", PtrPtr().get() != nullptr ? "passed" : "failed"); +// CHECK: Double pointer to private type: passed + +// Test 4: Const reference to private type +class ConstRef { using data_t = int; data_t val = 100; public: const data_t& get(); }; +const ConstRef::data_t& ConstRef::get() { return val; } +printf("Const reference to private type: %d\n", ConstRef().get()); +// CHECK: Const reference to private type: 100 + +// Test 5: Pointer to private nested struct +class Container { struct Node { int x; }; public: Node* create(); }; +Container::Node* Container::create() { return new Node{789}; } +printf("Pointer to private nested struct: %d\n", Container().create()->x); +// CHECK: Pointer to private nested struct: 789 + +%quit