Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2020,6 +2020,27 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(
CXXScopeSpec &SS, bool IsNewScope,
ImplicitTypenameContext AllowImplicitTypename) {
if (Tok.is(tok::identifier)) {
// In incremental/clang-repl mode, suppress access checks for qualified
// type lookups when no delayed diagnostic pool is active. This handles
// the case where we're parsing input like "A::B *A::foo()" where the type
// "A::B" might be a private member type, but if this turns out to be an
// out-of-line member function definition, access should be allowed.
//
// When the declaration is actually parsed (via ParseDeclarationOrFunctionDefinition),
// the ParsingDeclSpec will set up proper delayed diagnostics to handle
// access checking in the correct context.
//
// We only do this in incremental mode because this is where the issue
// manifests - disambiguation happens before ParsingDeclSpec is created.
// In normal compilation, these access checks would be re-triggered during
// actual parsing with delayed diagnostics active.
bool SuppressAccess = getLangOpts().IncrementalExtensions &&
SS.isNotEmpty() &&
!Actions.DelayedDiagnostics.shouldDelayDiagnostics();
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,
Expand Down
60 changes: 60 additions & 0 deletions clang/test/Interpreter/private-member-access.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// RUN: cat %s | clang-repl | FileCheck %s

extern "C" int printf(const char*, ...);

// Test 1: Private nested struct in return type
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

// Test 2: Private enum in return type
class Status { enum Code { OK = 0, ERROR = 1 }; public: Code get(); };
Status::Code Status::get() { return OK; }
printf("Private enum: %d\n", Status().get());
// CHECK: Private enum: 0

// Test 3: Template with private type alias
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

// Test 4: Protected type alias (not just private)
class ProtectedBase { protected: using value_type = int; public: value_type get(); };
ProtectedBase::value_type ProtectedBase::get() { return 42; }
printf("Protected type alias: %d\n", ProtectedBase().get());
// CHECK: Protected type alias: 42

// Test 5: Deeply nested private type (A::B::C)
class Outer { public: class Middle { struct Inner { int x; }; public: Inner* create(); }; };
Outer::Middle::Inner* Outer::Middle::create() { return new Inner{789}; }
printf("Deeply nested: %d\n", Outer::Middle().create()->x);
// CHECK: Deeply nested: 789

// Test 6: Private typedef (not using declaration)
class WithTypedef { typedef double real_t; public: real_t compute(); };
WithTypedef::real_t WithTypedef::compute() { return 2.718; }
printf("Private typedef: %.3f\n", WithTypedef().compute());
// CHECK: Private typedef: 2.718

// Test 7: Const-qualified return type with private type
class ConstReturn { using data_t = int; public: const data_t& get(); private: data_t val = 100; };
const ConstReturn::data_t& ConstReturn::get() { return val; }
printf("Const return: %d\n", ConstReturn().get());
// CHECK: Const return: 100

// Test 8: Reference return type with private type
class RefReturn { using ref_t = int; ref_t value = 55; public: ref_t& getRef(); };
RefReturn::ref_t& RefReturn::getRef() { return value; }
RefReturn rr; rr.getRef() = 66;
printf("Reference return: %d\n", rr.getRef());
// CHECK: Reference return: 66

// Test 9: Pointer-to-pointer with private type
class PtrPtr { using inner_t = int; public: inner_t** get(); };
PtrPtr::inner_t** PtrPtr::get() { static int* p = nullptr; return &p; }
printf("Pointer to pointer: passed\n");
// CHECK: Pointer to pointer: passed

%quit