[clang] [clang][ThreadSafety] Enable late parse for all capabilities, under the experimental flag (PR #212615)

Aaron Puchert via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 25 16:12:13 PDT 2026


================
@@ -701,6 +703,80 @@ void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D,
   LAs.clear();
 }
 
+/// Collect the references to parameters in \p Attrs' arguments.
+static void collectParamRefs(const ParsedAttributes &Attrs,
+                             SmallVectorImpl<const DeclRefExpr *> &Refs) {
+  SmallVector<const Stmt *, 8> Worklist;
+  for (const ParsedAttr &AL : Attrs)
+    for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I)
+      if (AL.isArgExpr(I))
+        Worklist.push_back(AL.getArgAsExpr(I));
+  while (!Worklist.empty()) {
+    const Stmt *S = Worklist.pop_back_val();
+    if (!S)
+      continue;
+    if (const auto *DRE = dyn_cast<DeclRefExpr>(S);
+        DRE && isa<ParmVarDecl>(DRE->getDecl()))
+      Refs.push_back(DRE);
+    llvm::append_range(Worklist, S->children());
+  }
+}
+
+bool Parser::checkLateAttributeParamRefs(
+    const LateParsedAttribute &LPA, const Decl *D,
+    ArrayRef<const DeclRefExpr *> ParamRefs, bool ReenteredProtoParams) {
+  auto IsPointeeParam = [&](const ParmVarDecl *PVD) {
+    return ReenteredProtoParams && llvm::is_contained(LPA.ProtoParams, PVD);
+  };
+
+  // In a C++ class, attributes were always late parsed and a pointee's
+  // parameters were not in scope, so a name that now binds to one used to bind
+  // to whatever else it names outside the prototype. Rather than silently
+  // change its meaning, reject the attribute as ambiguous.
+  if (getLangOpts().CPlusPlus && getCurScope()->isClassScope()) {
+    for (const DeclRefExpr *DRE : ParamRefs) {
+      const auto *PVD = cast<ParmVarDecl>(DRE->getDecl());
+      if (!IsPointeeParam(PVD))
+        continue;
+      LookupResult R(Actions, PVD->getDeclName(), DRE->getLocation(),
+                     Sema::LookupOrdinaryName);
+      if (!Actions.LookupName(R, getCurScope()) || R.isAmbiguous())
+        continue;
+      Diag(DRE->getLocation(), diag::err_ambiguous_reference)
+          << PVD->getDeclName();
+      Diag(PVD->getLocation(), diag::note_ambiguous_candidate) << PVD;
+      for (const NamedDecl *Other : R)
+        Diag(Other->getLocation(), diag::note_ambiguous_candidate) << Other;
+      return true;
+    }
+  }
+
+  // A name binds the same way in a template, but instantiation cannot yet map a
+  // pointee's parameters, which are instantiated with the declaration's type
+  // and not kept, nor a parameter declared after the one the attribute is on,
+  // which is instantiated after that parameter's attributes. Reject the
+  // attribute rather than instantiate it wrongly.
----------------
aaronpuchert wrote:

Sounds like this is related to not treating this as type attribute.

https://github.com/llvm/llvm-project/pull/212615


More information about the cfe-commits mailing list