[clang] [Clang] Implement C++26’s P2893R3 ‘Variadic friends’ (PR #101448)

via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 13 03:09:15 PDT 2024


================
@@ -3048,6 +3087,66 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration(
   if (DS.hasTagDefinition())
     Actions.ActOnDefinedDeclarationSpecifier(DS.getRepAsDecl());
 
+  // Handle C++26's variadic friend declarations. These don't even have
+  // declarators, so we get them out of the way early here.
+  if (DS.isFriendSpecifiedFirst() && Tok.isOneOf(tok::comma, tok::ellipsis)) {
+    SourceLocation FriendLoc = DS.getFriendSpecLoc();
+    SmallVector<Decl *> Decls;
+    auto DiagnoseCompat = [&, Diagnosed = false]() mutable {
+      if (Diagnosed)
+        return;
+      Diagnosed = true;
+      Diag(Tok.getLocation(), getLangOpts().CPlusPlus26
+                                  ? diag::warn_cxx23_variadic_friends
+                                  : diag::ext_variadic_friends);
+    };
+
+    // Handles a single friend-type-specifier.
+    auto ParsedFriendDecl = [&](ParsingDeclSpec &DeclSpec) {
+      bool Variadic = Tok.is(tok::ellipsis);
+      RecordDecl *AnonRecord = nullptr;
+      Decl *D = Actions.ParsedFreeStandingDeclSpec(
+          getCurScope(), AS, DeclSpec, DeclAttrs, TemplateParams, false,
+          AnonRecord, Variadic ? Tok.getLocation() : SourceLocation());
+      DeclSpec.complete(D);
+      if (!D) {
+        SkipUntil(tok::semi, tok::r_brace);
+        return true;
+      }
+
+      // Eat the '...'.
+      if (Variadic) {
+        DiagnoseCompat();
+        ConsumeToken();
+      }
+
+      Decls.push_back(D);
+      return false;
+    };
+
+    if (ParsedFriendDecl(DS))
+      return nullptr;
+
+    if (Tok.is(tok::comma))
+      DiagnoseCompat();
+
+    while (TryConsumeToken(tok::comma)) {
+      ParsingDeclSpec DeclSpec(*this, TemplateDiags);
+      const char *PrevSpec = nullptr;
+      unsigned DiagId = 0;
+      DeclSpec.SetFriendSpec(FriendLoc, PrevSpec, DiagId);
+      ParseDeclarationSpecifiers(DeclSpec, TemplateInfo, AS,
+                                 DeclSpecContext::DSC_class, nullptr);
+      if (ParsedFriendDecl(DeclSpec))
+        return nullptr;
+    }
----------------
Sirraide wrote:

I’ve cleaned up the code around this a bit, but I’m not sure I can restructure this to a do while loop because the argument to `ParsedFriendDecl` in the loop is different (and I don’t think you can reuse a `ParsingDeclSpec`, or can you?)

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


More information about the cfe-commits mailing list