[clang] [clang-repl] Fix disambiguation of out-of-line member with private types (PR #178842)
Vassil Vassilev via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 11 21:56:25 PST 2026
https://github.com/vgvassilev updated https://github.com/llvm/llvm-project/pull/178842
>From 67e8227439658d258432d4926df975626dfba483 Mon Sep 17 00:00:00 2001
From: fogsong233 <fogsong233 at gmail.com>
Date: Tue, 10 Feb 2026 23:15:08 +0800
Subject: [PATCH] [clang-repl] Fix disambiguation of out-of-line member with
private types
This patch fixes a bug in clang-repl where out-of-line member function
definitions were incorrectly identified as statements when they involved
private type aliases.
The issue occurred because `isCXXDeclarationStatement` would trigger
immediate access checks during tentative parsing. Since the context of
an out-of-line definition isn't fully established during this phase,
Sema would incorrectly flag private members as inaccessible, causing
the parser to fail the declaration check and fall back to statement
parsing.
Changes:
- In `isCXXDeclarationStatement`, use `TentativeParsingAction` to
ensure the token stream is fully restored.
- Use `SuppressAccessChecks` during the tentative disambiguation phase
to prevent premature access errors.
- Ensure that formal access verification still occurs during the
actual parsing phase in `ParseDeclarationOrFunctionDefinition`.
- Add tests and resolve a FIXME in
clang/test/Interpreter/disambiguate-decl-stmt.cpp.
Fixes llvm#164885.
See also jank-lang/jank#609.
---
clang/lib/Parse/ParseTentative.cpp | 16 ++++++++++++++++
clang/test/Interpreter/access.cpp | 15 +++++++++++++++
.../test/Interpreter/disambiguate-decl-stmt.cpp | 5 ++---
3 files changed, 33 insertions(+), 3 deletions(-)
create mode 100644 clang/test/Interpreter/access.cpp
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 9622a00687ca5..c8ddc120aa87e 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/ParsedTemplate.h"
using namespace clang;
@@ -78,6 +79,21 @@ bool Parser::isCXXDeclarationStatement(
[[fallthrough]];
// simple-declaration
default:
+
+ if (DisambiguatingWithExpression) {
+ TentativeParsingAction TPA(*this, /*Unannotated=*/true);
+ // Skip early access checks to support edge cases like extern declarations
+ // involving private types. Tokens are unannotated by reverting so that
+ // access integrity is verified during the subsequent type-lookup phase.
+ SuppressAccessChecks AccessExporter(*this, /*activate=*/true);
+ if (isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false)) {
+ // Do not annotate the tokens, otherwise access will be neglected later.
+ TPA.Revert();
+ return true;
+ }
+ TPA.Commit();
+ return false;
+ }
return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false);
}
}
diff --git a/clang/test/Interpreter/access.cpp b/clang/test/Interpreter/access.cpp
new file mode 100644
index 0000000000000..c6b535bc1db92
--- /dev/null
+++ b/clang/test/Interpreter/access.cpp
@@ -0,0 +1,15 @@
+// REQUIRES: host-supports-jit
+// RUN: cat %s | clang-repl 2>&1 | FileCheck %s
+
+struct A { };
+
+class B { using u = A; const static int p = 1; public: u *foo(); };
+
+B::u* foo() { return nullptr; }
+// CHECK: error: 'u' is a private member of 'B'
+
+B::u * B::foo() { return nullptr; }
+// CHECK-NOT: error: 'u' is a private member of 'B'
+
+int p = B::p;
+// CHECK: error: 'p' is a private member of 'B'
diff --git a/clang/test/Interpreter/disambiguate-decl-stmt.cpp b/clang/test/Interpreter/disambiguate-decl-stmt.cpp
index 1f4d5e267288b..24902cee8ed1f 100644
--- a/clang/test/Interpreter/disambiguate-decl-stmt.cpp
+++ b/clang/test/Interpreter/disambiguate-decl-stmt.cpp
@@ -70,11 +70,10 @@ class PrivateUsingFriendVar { static PrivateUsingFriend::T i; };
PrivateUsingFriend::T PrivateUsingFriendVar::i = 42;
// The following should still diagnose (inspired by PR13642)
-// FIXME: Should not be diagnosed twice!
class PR13642 { class Inner { public: static int i; }; };
-// expected-note at -1 2 {{implicitly declared private here}}
+// expected-note at -1 {{implicitly declared private here}}
PR13642::Inner::i = 5;
-// expected-error at -1 2 {{'Inner' is a private member of 'PR13642'}}
+// expected-error at -1 {{'Inner' is a private member of 'PR13642'}}
// Deduction guide
template<typename T> struct A { A(); A(T); };
More information about the cfe-commits
mailing list