[llvm-branch-commits] [clang] 9254010 - [clang-repl] Fix disambiguation of out-of-line member with private types (#178842)
Cullen Rhodes via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Feb 16 00:56:41 PST 2026
Author: fogsong233
Date: 2026-02-16T08:56:33Z
New Revision: 92540107d316fccbca038cdadc2206f4b113a5a4
URL: https://github.com/llvm/llvm-project/commit/92540107d316fccbca038cdadc2206f4b113a5a4
DIFF: https://github.com/llvm/llvm-project/commit/92540107d316fccbca038cdadc2206f4b113a5a4.diff
LOG: [clang-repl] Fix disambiguation of out-of-line member with private types (#178842)
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.
(cherry picked from commit f6f0503673b746a2e43a995006ced39c5c7e412e)
Added:
clang/test/Interpreter/access.cpp
Modified:
clang/lib/Parse/ParseTentative.cpp
clang/test/Interpreter/disambiguate-decl-stmt.cpp
Removed:
################################################################################
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 llvm-branch-commits
mailing list