================
@@ -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());
----------------
vtjnash wrote:

Claude couldn't think of any way to show that this was previously wrong, but 
agreed that we should have some specific tests for it, and that your version 
was more clear.

https://github.com/llvm/llvm-project/pull/212615
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to