[clang] [clang][ThreadSafety] Enable late parse for all capabilities, under the experimental flag (PR #212615)
Marco Elver via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 25 07:26:36 PDT 2026
================
@@ -715,6 +717,79 @@ 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.
+ // FIXME: Map these parameters during template instantiation.
+ if (Actions.CurContext->isDependentContext() ||
+ getCurScope()->getTemplateParamParent() ||
+ Actions.getCurGenericLambda()) {
+ const SourceManager &SM = PP.getSourceManager();
+ for (const DeclRefExpr *DRE : ParamRefs) {
+ const auto *PVD = cast<ParmVarDecl>(DRE->getDecl());
----------------
melver wrote:
Checking whether PVD is a later parameter of the same prototype via SM.isBeforeInTranslationUnit can be sensitive to macro expansions and doesn't verify that D and PVD are at the same prototype nesting depth.
Does this work instead?
```
- const SourceManager &SM = PP.getSourceManager();
+ const auto *DParam = dyn_cast_or_null<ParmVarDecl>(D);
for (const DeclRefExpr *DRE : ParamRefs) {
const auto *PVD = cast<ParmVarDecl>(DRE->getDecl());
bool Pointee = IsPointeeParam(PVD);
if (!Pointee &&
- !(isa<ParmVarDecl>(D) &&
- SM.isBeforeInTranslationUnit(D->getLocation(), PVD->getLocation())))
+ !(DParam &&
+ DParam->getFunctionScopeDepth() == PVD->getFunctionScopeDepth() &&
+ DParam->getFunctionScopeIndex() < PVD->getFunctionScopeIndex()))
continue;
```
https://github.com/llvm/llvm-project/pull/212615
More information about the cfe-commits
mailing list