From 2b0a8fcf702fb63fca8ec6e11dca35baf70f058d Mon Sep 17 00:00:00 2001 From: Sirraide Date: Thu, 15 Aug 2024 21:16:30 +0200 Subject: [PATCH] =?UTF-8?q?[Clang]=20Implement=20C++26=E2=80=99s=20P2893R3?= =?UTF-8?q?=20=E2=80=98Variadic=20friends=E2=80=99=20(#101448)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement P2893R3 ‘Variadic friends’ for C++26. This closes #98587. Co-authored-by: Younan Zhang --- clang/docs/LanguageExtensions.rst | 1 + clang/docs/ReleaseNotes.rst | 2 + clang/include/clang/AST/DeclFriend.h | 39 +- .../clang/Basic/DiagnosticParseKinds.td | 6 + .../clang/Basic/DiagnosticSemaKinds.td | 4 + clang/include/clang/Sema/Sema.h | 7 +- clang/lib/AST/ASTImporter.cpp | 7 +- clang/lib/AST/DeclFriend.cpp | 14 +- clang/lib/AST/DeclPrinter.cpp | 5 +- clang/lib/AST/JSONNodeDumper.cpp | 1 + clang/lib/AST/ODRHash.cpp | 1 + clang/lib/AST/TextNodeDumper.cpp | 2 + clang/lib/Frontend/InitPreprocessor.cpp | 1 + clang/lib/Parse/ParseDeclCXX.cpp | 98 +++- clang/lib/Sema/SemaDecl.cpp | 8 +- clang/lib/Sema/SemaDeclCXX.cpp | 53 ++- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 43 +- clang/lib/Serialization/ASTReaderDecl.cpp | 1 + clang/lib/Serialization/ASTWriterDecl.cpp | 1 + clang/test/AST/ast-dump-funcs-json.cpp | 441 +++++++++++++----- clang/test/AST/cxx2c-variadic-friends.cpp | 81 ++++ clang/test/CXX/drs/cwg29xx.cpp | 25 + clang/test/Lexer/cxx-features.cpp | 4 + .../cxx2c-variadic-friends-ext-diags.cpp | 16 + clang/test/Parser/cxx2c-variadic-friends.cpp | 91 ++++ clang/test/SemaCXX/cxx2c-variadic-friends.cpp | 156 +++++++ clang/www/cxx_dr_status.html | 2 +- clang/www/cxx_status.html | 2 +- 28 files changed, 942 insertions(+), 170 deletions(-) create mode 100644 clang/test/AST/cxx2c-variadic-friends.cpp create mode 100644 clang/test/CXX/drs/cwg29xx.cpp create mode 100644 clang/test/Parser/cxx2c-variadic-friends-ext-diags.cpp create mode 100644 clang/test/Parser/cxx2c-variadic-friends.cpp create mode 100644 clang/test/SemaCXX/cxx2c-variadic-friends.cpp diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 4679dbb68b25e..114e742f3561b 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1505,6 +1505,7 @@ Attributes on Lambda-Expressions C+ Attributes on Structured Bindings __cpp_structured_bindings C++26 C++03 Pack Indexing __cpp_pack_indexing C++26 C++03 ``= delete ("should have a reason");`` __cpp_deleted_function C++26 C++03 +Variadic Friends __cpp_variadic_friend C++26 C++03 -------------------------------------------- -------------------------------- ------------- ------------- Designated initializers (N494) C99 C89 Array & element qualification (N2607) C23 C89 diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 68cf79928bda0..14f1eecc5748e 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -126,6 +126,8 @@ C++2c Feature Support - Add ``__builtin_is_virtual_base_of`` intrinsic, which supports `P2985R0 A type trait for detecting virtual base classes `_ +- Implemented `P2893R3 Variadic Friends `_ + Resolutions to C++ Defect Reports ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/AST/DeclFriend.h b/clang/include/clang/AST/DeclFriend.h index 9789282f351a5..095f14a81fd57 100644 --- a/clang/include/clang/AST/DeclFriend.h +++ b/clang/include/clang/AST/DeclFriend.h @@ -70,6 +70,9 @@ class FriendDecl final // Location of the 'friend' specifier. SourceLocation FriendLoc; + // Location of the '...', if present. + SourceLocation EllipsisLoc; + /// True if this 'friend' declaration is unsupported. Eventually we /// will support every possible friend declaration, but for now we /// silently ignore some and set this flag to authorize all access. @@ -82,10 +85,11 @@ class FriendDecl final unsigned NumTPLists : 31; FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend, - SourceLocation FriendL, + SourceLocation FriendL, SourceLocation EllipsisLoc, ArrayRef FriendTypeTPLists) : Decl(Decl::Friend, DC, L), Friend(Friend), FriendLoc(FriendL), - UnsupportedFriend(false), NumTPLists(FriendTypeTPLists.size()) { + EllipsisLoc(EllipsisLoc), UnsupportedFriend(false), + NumTPLists(FriendTypeTPLists.size()) { for (unsigned i = 0; i < NumTPLists; ++i) getTrailingObjects()[i] = FriendTypeTPLists[i]; } @@ -110,7 +114,7 @@ class FriendDecl final static FriendDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend_, - SourceLocation FriendL, + SourceLocation FriendL, SourceLocation EllipsisLoc = {}, ArrayRef FriendTypeTPLists = std::nullopt); static FriendDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned FriendTypeNumTPLists); @@ -143,8 +147,24 @@ class FriendDecl final return FriendLoc; } + /// Retrieves the location of the '...', if present. + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + /// Retrieves the source range for the friend declaration. SourceRange getSourceRange() const override LLVM_READONLY { + if (TypeSourceInfo *TInfo = getFriendType()) { + SourceLocation StartL = + (NumTPLists == 0) ? getFriendLoc() + : getTrailingObjects()[0] + ->getTemplateLoc(); + SourceLocation EndL = isPackExpansion() ? getEllipsisLoc() + : TInfo->getTypeLoc().getEndLoc(); + return SourceRange(StartL, EndL); + } + + if (isPackExpansion()) + return SourceRange(getFriendLoc(), getEllipsisLoc()); + if (NamedDecl *ND = getFriendDecl()) { if (const auto *FD = dyn_cast(ND)) return FD->getSourceRange(); @@ -158,15 +178,8 @@ class FriendDecl final } return SourceRange(getFriendLoc(), ND->getEndLoc()); } - else if (TypeSourceInfo *TInfo = getFriendType()) { - SourceLocation StartL = - (NumTPLists == 0) ? getFriendLoc() - : getTrailingObjects()[0] - ->getTemplateLoc(); - return SourceRange(StartL, TInfo->getTypeLoc().getEndLoc()); - } - else - return SourceRange(getFriendLoc(), getLocation()); + + return SourceRange(getFriendLoc(), getLocation()); } /// Determines if this friend kind is unsupported. @@ -177,6 +190,8 @@ class FriendDecl final UnsupportedFriend = Unsupported; } + bool isPackExpansion() const { return EllipsisLoc.isValid(); } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Decl::Friend; } diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 12aab09f28556..62a97b36737e7 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -965,6 +965,12 @@ def warn_cxx23_delete_with_message : Warning< "'= delete' with a message is incompatible with C++ standards before C++2c">, DefaultIgnore, InGroup; +def ext_variadic_friends : ExtWarn< + "variadic 'friend' declarations are a C++2c extension">, InGroup; +def warn_cxx23_variadic_friends : Warning< + "variadic 'friend' declarations are incompatible with C++ standards before C++2c">, + DefaultIgnore, InGroup; + // C++11 default member initialization def ext_nonstatic_member_init : ExtWarn< "default member initializer for non-static data member is a C++11 " diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 461eeb19f65e4..8a92973236ddb 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1741,6 +1741,10 @@ def ext_friend_tag_redecl_outside_namespace : ExtWarn< "enclosing namespace is a Microsoft extension; add a nested name specifier">, InGroup; def err_pure_friend : Error<"friend declaration cannot have a pure-specifier">; +def err_friend_template_decl_multiple_specifiers: Error< + "a friend declaration that befriends a template must contain exactly one type-specifier">; +def friend_template_decl_malformed_pack_expansion : Error< + "friend declaration expands pack %0 that is declared it its own template parameter list">; def err_invalid_base_in_interface : Error< "interface type cannot inherit from " diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a025ff6fc13f3..88e82dca007b8 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3800,7 +3800,8 @@ class Sema final : public SemaBase { const ParsedAttributesView &DeclAttrs, MultiTemplateParamsArg TemplateParams, bool IsExplicitInstantiation, - RecordDecl *&AnonRecord); + RecordDecl *&AnonRecord, + SourceLocation EllipsisLoc = {}); /// BuildAnonymousStructOrUnion - Handle the declaration of an /// anonymous structure or union. Anonymous unions are a C++ feature @@ -5538,7 +5539,8 @@ class Sema final : public SemaBase { /// parameters present at all, require proper matching, i.e. /// template <> template \ friend class A::B; Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, - MultiTemplateParamsArg TemplateParams); + MultiTemplateParamsArg TemplateParams, + SourceLocation EllipsisLoc); NamedDecl *ActOnFriendFunctionDecl(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParams); @@ -5852,6 +5854,7 @@ class Sema final : public SemaBase { unsigned TagSpec, SourceLocation TagLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, + SourceLocation EllipsisLoc, const ParsedAttributesView &Attr, MultiTemplateParamsArg TempParamLists); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 198bc34a9f031..3bc0a647ebf94 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -4429,11 +4429,14 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) { auto FriendLocOrErr = import(D->getFriendLoc()); if (!FriendLocOrErr) return FriendLocOrErr.takeError(); + auto EllipsisLocOrErr = import(D->getEllipsisLoc()); + if (!EllipsisLocOrErr) + return EllipsisLocOrErr.takeError(); FriendDecl *FrD; if (GetImportedOrCreateDecl(FrD, D, Importer.getToContext(), DC, - *LocationOrErr, ToFU, - *FriendLocOrErr, ToTPLists)) + *LocationOrErr, ToFU, *FriendLocOrErr, + *EllipsisLocOrErr, ToTPLists)) return FrD; FrD->setAccess(D->getAccess()); diff --git a/clang/lib/AST/DeclFriend.cpp b/clang/lib/AST/DeclFriend.cpp index 04b9b93699f36..8b285bfce8d52 100644 --- a/clang/lib/AST/DeclFriend.cpp +++ b/clang/lib/AST/DeclFriend.cpp @@ -31,11 +31,11 @@ FriendDecl *FriendDecl::getNextFriendSlowCase() { NextFriend.get(getASTContext().getExternalSource())); } -FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - FriendUnion Friend, - SourceLocation FriendL, - ArrayRef FriendTypeTPLists) { +FriendDecl * +FriendDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + FriendUnion Friend, SourceLocation FriendL, + SourceLocation EllipsisLoc, + ArrayRef FriendTypeTPLists) { #ifndef NDEBUG if (Friend.is()) { const auto *D = Friend.get(); @@ -56,8 +56,8 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, std::size_t Extra = FriendDecl::additionalSizeToAlloc( FriendTypeTPLists.size()); - auto *FD = new (C, DC, Extra) FriendDecl(DC, L, Friend, FriendL, - FriendTypeTPLists); + auto *FD = new (C, DC, Extra) + FriendDecl(DC, L, Friend, FriendL, EllipsisLoc, FriendTypeTPLists); cast(DC)->pushFriendDecl(FD); return FD; } diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 26773a69ab9ac..07be813abd8ad 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -868,7 +868,7 @@ void DeclPrinter::VisitFriendDecl(FriendDecl *D) { for (unsigned i = 0; i < NumTPLists; ++i) printTemplateParameters(D->getFriendTypeTemplateParameterList(i)); Out << "friend "; - Out << " " << TSI->getType().getAsString(Policy); + Out << TSI->getType().getAsString(Policy); } else if (FunctionDecl *FD = dyn_cast(D->getFriendDecl())) { @@ -885,6 +885,9 @@ void DeclPrinter::VisitFriendDecl(FriendDecl *D) { Out << "friend "; VisitRedeclarableTemplateDecl(CTD); } + + if (D->isPackExpansion()) + Out << "..."; } void DeclPrinter::VisitFieldDecl(FieldDecl *D) { diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index f8f80c8c25157..565f1e05710c8 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -1090,6 +1090,7 @@ void JSONNodeDumper::VisitAccessSpecDecl(const AccessSpecDecl *ASD) { void JSONNodeDumper::VisitFriendDecl(const FriendDecl *FD) { if (const TypeSourceInfo *T = FD->getFriendType()) JOS.attribute("type", createQualType(T->getType())); + attributeOnlyIfTrue("isPackExpansion", FD->isPackExpansion()); } void JSONNodeDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) { diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index fbfe92318dc5e..b748093831e3f 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -461,6 +461,7 @@ class ODRDeclVisitor : public ConstDeclVisitor { } else { AddDecl(D->getFriendDecl()); } + Hash.AddBoolean(D->isPackExpansion()); } void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index d50d4c7028c69..2c962253c8bea 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -2697,6 +2697,8 @@ void TextNodeDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) { void TextNodeDumper::VisitFriendDecl(const FriendDecl *D) { if (TypeSourceInfo *T = D->getFriendType()) dumpType(T->getType()); + if (D->isPackExpansion()) + OS << "..."; } void TextNodeDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) { diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 8e62461d8a181..4f2856dd2247f 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -765,6 +765,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, // C++26 features supported in earlier language modes. Builder.defineMacro("__cpp_pack_indexing", "202311L"); Builder.defineMacro("__cpp_deleted_function", "202403L"); + Builder.defineMacro("__cpp_variadic_friend", "202403L"); if (LangOpts.Char8) Builder.defineMacro("__cpp_char8_t", "202207L"); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index d45a738fe4c59..18c5fe6056b47 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -452,7 +452,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) { /// /// export-function-declaration: /// 'export' function-declaration -/// +/// /// export-declaration-group: /// 'export' '{' function-declaration-seq[opt] '}' /// @@ -2007,9 +2007,16 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy(); TagUseKind TUK; - if (isDefiningTypeSpecifierContext(DSC, getLangOpts().CPlusPlus) == - AllowDefiningTypeSpec::No || - (getLangOpts().OpenMP && OpenMPDirectiveParsing)) + + // C++26 [class.mem.general]p10: If a name-declaration matches the + // syntactic requirements of friend-type-declaration, it is a + // friend-type-declaration. + if (getLangOpts().CPlusPlus && DS.isFriendSpecifiedFirst() && + Tok.isOneOf(tok::comma, tok::ellipsis)) + TUK = TagUseKind::Friend; + else if (isDefiningTypeSpecifierContext(DSC, getLangOpts().CPlusPlus) == + AllowDefiningTypeSpec::No || + (getLangOpts().OpenMP && OpenMPDirectiveParsing)) TUK = TagUseKind::Reference; else if (Tok.is(tok::l_brace) || (DSC != DeclSpecContext::DSC_association && @@ -2241,9 +2248,28 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, diag::err_keyword_not_allowed, /*DiagnoseEmptyAttrs=*/true); + // Consume '...' first so we error on the ',' after it if there is one. + SourceLocation EllipsisLoc; + TryConsumeToken(tok::ellipsis, EllipsisLoc); + + // CWG 2917: In a template-declaration whose declaration is a + // friend-type-declaration, the friend-type-specifier-list shall + // consist of exactly one friend-type-specifier. + // + // Essentially, the following is obviously nonsense, so disallow it: + // + // template + // friend class S, int; + // + if (Tok.is(tok::comma)) { + Diag(Tok.getLocation(), + diag::err_friend_template_decl_multiple_specifiers); + SkipUntil(tok::semi, StopBeforeMatch); + } + TagOrTempResult = Actions.ActOnTemplatedFriendTag( getCurScope(), DS.getFriendSpecLoc(), TagType, StartLoc, SS, Name, - NameLoc, attrs, + NameLoc, EllipsisLoc, attrs, MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0] : nullptr, TemplateParams ? TemplateParams->size() : 0)); } else { @@ -2818,6 +2844,7 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq( /// member-declaration: /// decl-specifier-seq[opt] member-declarator-list[opt] ';' /// function-definition ';'[opt] +/// [C++26] friend-type-declaration /// ::[opt] nested-name-specifier template[opt] unqualified-id ';'[TODO] /// using-declaration [TODO] /// [C++0x] static_assert-declaration @@ -2850,6 +2877,18 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq( /// constant-initializer: /// '=' constant-expression /// +/// friend-type-declaration: +/// 'friend' friend-type-specifier-list ; +/// +/// friend-type-specifier-list: +/// friend-type-specifier ...[opt] +/// friend-type-specifier-list , friend-type-specifier ...[opt] +/// +/// friend-type-specifier: +/// simple-type-specifier +/// elaborated-type-specifier +/// typename-specifier +/// Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration( AccessSpecifier AS, ParsedAttributes &AccessAttrs, ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject *TemplateDiags) { @@ -3051,6 +3090,55 @@ 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)) { + Diag(Tok.getLocation(), getLangOpts().CPlusPlus26 + ? diag::warn_cxx23_variadic_friends + : diag::ext_variadic_friends); + + SourceLocation FriendLoc = DS.getFriendSpecLoc(); + SmallVector Decls; + + // Handles a single friend-type-specifier. + auto ParsedFriendDecl = [&](ParsingDeclSpec &DeclSpec) { + SourceLocation VariadicLoc; + TryConsumeToken(tok::ellipsis, VariadicLoc); + + RecordDecl *AnonRecord = nullptr; + Decl *D = Actions.ParsedFreeStandingDeclSpec( + getCurScope(), AS, DeclSpec, DeclAttrs, TemplateParams, false, + AnonRecord, VariadicLoc); + DeclSpec.complete(D); + if (!D) { + SkipUntil(tok::semi, tok::r_brace); + return true; + } + + Decls.push_back(D); + return false; + }; + + if (ParsedFriendDecl(DS)) + return nullptr; + + 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; + } + + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_stmt, + "friend declaration"); + + return Actions.BuildDeclaratorGroup(Decls); + } + ParsingDeclarator DeclaratorInfo(*this, DS, DeclAttrs, DeclaratorContext::Member); if (TemplateInfo.TemplateParams) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 641b180527da5..83a652691e2e0 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5000,7 +5000,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, const ParsedAttributesView &DeclAttrs, MultiTemplateParamsArg TemplateParams, bool IsExplicitInstantiation, - RecordDecl *&AnonRecord) { + RecordDecl *&AnonRecord, + SourceLocation EllipsisLoc) { Decl *TagD = nullptr; TagDecl *Tag = nullptr; if (DS.getTypeSpecType() == DeclSpec::TST_class || @@ -5067,9 +5068,12 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, // whatever routines created it handled the friendship aspect. if (TagD && !Tag) return nullptr; - return ActOnFriendTypeDecl(S, DS, TemplateParams); + return ActOnFriendTypeDecl(S, DS, TemplateParams, EllipsisLoc); } + assert(EllipsisLoc.isInvalid() && + "Friend ellipsis but not friend-specified?"); + // Track whether this decl-specifier declares anything. bool DeclaresAnything = true; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 9ca91a2def39f..e05595e565d54 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -17386,7 +17386,8 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, DeclResult Sema::ActOnTemplatedFriendTag( Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, - const ParsedAttributesView &Attr, MultiTemplateParamsArg TempParamLists) { + SourceLocation EllipsisLoc, const ParsedAttributesView &Attr, + MultiTemplateParamsArg TempParamLists) { TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); bool IsMemberSpecialization = false; @@ -17430,6 +17431,7 @@ DeclResult Sema::ActOnTemplatedFriendTag( // If it's explicit specializations all the way down, just forget // about the template header and build an appropriate non-templated // friend. TODO: for source fidelity, remember the headers. + NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); if (isAllExplicitSpecializations) { if (SS.isEmpty()) { bool Owned = false; @@ -17445,7 +17447,6 @@ DeclResult Sema::ActOnTemplatedFriendTag( /*IsTemplateParamOrArg=*/false, /*OOK=*/OOK_Outside); } - NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); ElaboratedTypeKeyword Keyword = TypeWithKeyword::getKeywordForTagTypeKind(Kind); QualType T = CheckTypenameType(Keyword, TagLoc, QualifierLoc, @@ -17467,8 +17468,9 @@ DeclResult Sema::ActOnTemplatedFriendTag( TL.getNamedTypeLoc().castAs().setNameLoc(NameLoc); } - FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc, - TSI, FriendLoc, TempParamLists); + FriendDecl *Friend = + FriendDecl::Create(Context, CurContext, NameLoc, TSI, FriendLoc, + EllipsisLoc, TempParamLists); Friend->setAccess(AS_public); CurContext->addDecl(Friend); return Friend; @@ -17476,7 +17478,22 @@ DeclResult Sema::ActOnTemplatedFriendTag( assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?"); - + // CWG 2917: if it (= the friend-type-specifier) is a pack expansion + // (13.7.4 [temp.variadic]), any packs expanded by that pack expansion + // shall not have been introduced by the template-declaration. + SmallVector Unexpanded; + collectUnexpandedParameterPacks(QualifierLoc, Unexpanded); + unsigned FriendDeclDepth = TempParamLists.front()->getDepth(); + for (UnexpandedParameterPack &U : Unexpanded) { + if (getDepthAndIndex(U).first >= FriendDeclDepth) { + auto *ND = U.first.dyn_cast(); + if (!ND) + ND = U.first.get()->getDecl(); + Diag(U.second, diag::friend_template_decl_malformed_pack_expansion) + << ND->getDeclName() << SourceRange(SS.getBeginLoc(), EllipsisLoc); + return true; + } + } // Handle the case of a templated-scope friend class. e.g. // template class A::B; @@ -17491,8 +17508,9 @@ DeclResult Sema::ActOnTemplatedFriendTag( TL.setQualifierLoc(SS.getWithLocInContext(Context)); TL.setNameLoc(NameLoc); - FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc, - TSI, FriendLoc, TempParamLists); + FriendDecl *Friend = + FriendDecl::Create(Context, CurContext, NameLoc, TSI, FriendLoc, + EllipsisLoc, TempParamLists); Friend->setAccess(AS_public); Friend->setUnsupportedFriend(true); CurContext->addDecl(Friend); @@ -17500,7 +17518,8 @@ DeclResult Sema::ActOnTemplatedFriendTag( } Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, - MultiTemplateParamsArg TempParams) { + MultiTemplateParamsArg TempParams, + SourceLocation EllipsisLoc) { SourceLocation Loc = DS.getBeginLoc(); SourceLocation FriendLoc = DS.getFriendSpecLoc(); @@ -17541,8 +17560,18 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, if (TheDeclarator.isInvalidType()) return nullptr; - if (DiagnoseUnexpandedParameterPack(Loc, TSI, UPPC_FriendDeclaration)) + // If '...' is present, the type must contain an unexpanded parameter + // pack, and vice versa. + bool Invalid = false; + if (EllipsisLoc.isInvalid() && + DiagnoseUnexpandedParameterPack(Loc, TSI, UPPC_FriendDeclaration)) return nullptr; + if (EllipsisLoc.isValid() && + !TSI->getType()->containsUnexpandedParameterPack()) { + Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) + << TSI->getTypeLoc().getSourceRange(); + Invalid = true; + } if (!T->isElaboratedTypeSpecifier()) { if (TempParams.size()) { @@ -17588,11 +17617,12 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, Decl *D; if (!TempParams.empty()) + // TODO: Support variadic friend template decls? D = FriendTemplateDecl::Create(Context, CurContext, Loc, TempParams, TSI, FriendLoc); else D = FriendDecl::Create(Context, CurContext, TSI->getTypeLoc().getBeginLoc(), - TSI, FriendLoc); + TSI, FriendLoc, EllipsisLoc); if (!D) return nullptr; @@ -17600,6 +17630,9 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, D->setAccess(AS_public); CurContext->addDecl(D); + if (Invalid) + D->setInvalidDecl(); + return D; } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index f93cd113988ae..14ca29f1bc3f1 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1442,8 +1442,47 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { if (D->isUnsupportedFriend()) { InstTy = Ty; } else { - InstTy = SemaRef.SubstType(Ty, TemplateArgs, - D->getLocation(), DeclarationName()); + if (D->isPackExpansion()) { + SmallVector Unexpanded; + SemaRef.collectUnexpandedParameterPacks(Ty->getTypeLoc(), Unexpanded); + assert(!Unexpanded.empty() && "Pack expansion without packs"); + + bool ShouldExpand = true; + bool RetainExpansion = false; + std::optional NumExpansions; + if (SemaRef.CheckParameterPacksForExpansion( + D->getEllipsisLoc(), D->getSourceRange(), Unexpanded, + TemplateArgs, ShouldExpand, RetainExpansion, NumExpansions)) + return nullptr; + + assert(!RetainExpansion && + "should never retain an expansion for a variadic friend decl"); + + if (ShouldExpand) { + SmallVector Decls; + for (unsigned I = 0; I != *NumExpansions; I++) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I); + TypeSourceInfo *TSI = SemaRef.SubstType( + Ty, TemplateArgs, D->getEllipsisLoc(), DeclarationName()); + if (!TSI) + return nullptr; + + auto FD = + FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), + TSI, D->getFriendLoc()); + + FD->setAccess(AS_public); + Owner->addDecl(FD); + Decls.push_back(FD); + } + + // Just drop this node; we have no use for it anymore. + return nullptr; + } + } + + InstTy = SemaRef.SubstType(Ty, TemplateArgs, D->getLocation(), + DeclarationName()); } if (!InstTy) return nullptr; diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index a9199f7e50f5d..ef160228933c5 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2361,6 +2361,7 @@ void ASTDeclReader::VisitFriendDecl(FriendDecl *D) { D->NextFriend = readDeclID().getRawValue(); D->UnsupportedFriend = (Record.readInt() != 0); D->FriendLoc = readSourceLocation(); + D->EllipsisLoc = readSourceLocation(); } void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) { diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 8a4ca54349e38..555f6325da646 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1660,6 +1660,7 @@ void ASTDeclWriter::VisitFriendDecl(FriendDecl *D) { Record.AddDeclRef(D->getNextFriend()); Record.push_back(D->UnsupportedFriend); Record.AddSourceLocation(D->FriendLoc); + Record.AddSourceLocation(D->EllipsisLoc); Code = serialization::DECL_FRIEND; } diff --git a/clang/test/AST/ast-dump-funcs-json.cpp b/clang/test/AST/ast-dump-funcs-json.cpp index 041d98f2713d3..957df5cea6ec5 100644 --- a/clang/test/AST/ast-dump-funcs-json.cpp +++ b/clang/test/AST/ast-dump-funcs-json.cpp @@ -41,13 +41,18 @@ int main() { Test1(); // Causes this to be marked 'used' } +template +struct TestFriends { + friend Ts...; +}; + // NOTE: CHECK lines have been autogenerated by gen_ast_dump_json_test.py // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "CXXMethodDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 124, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 4, // CHECK-NEXT: "col": 8, @@ -55,12 +60,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 119, // CHECK-NEXT: "col": 3, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 130, // CHECK-NEXT: "col": 14, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -76,7 +81,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "CXXMethodDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 140, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 5, // CHECK-NEXT: "col": 8, @@ -84,12 +89,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 135, // CHECK-NEXT: "col": 3, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 148, // CHECK-NEXT: "col": 16, // CHECK-NEXT: "tokLen": 5 // CHECK-NEXT: } @@ -105,7 +110,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "CXXMethodDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 162, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 6, // CHECK-NEXT: "col": 8, @@ -113,12 +118,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 157, // CHECK-NEXT: "col": 3, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 170, // CHECK-NEXT: "col": 16, // CHECK-NEXT: "tokLen": 8 // CHECK-NEXT: } @@ -134,7 +139,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "CXXMethodDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 187, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 7, // CHECK-NEXT: "col": 8, @@ -142,12 +147,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 182, // CHECK-NEXT: "col": 3, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 195, // CHECK-NEXT: "col": 16, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -163,7 +168,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "CXXMethodDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 205, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 8, // CHECK-NEXT: "col": 8, @@ -171,12 +176,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 200, // CHECK-NEXT: "col": 3, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 213, // CHECK-NEXT: "col": 16, // CHECK-NEXT: "tokLen": 2 // CHECK-NEXT: } @@ -192,7 +197,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "CXXMethodDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 232, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 9, // CHECK-NEXT: "col": 16, @@ -200,12 +205,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 219, // CHECK-NEXT: "col": 3, // CHECK-NEXT: "tokLen": 7 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 253, // CHECK-NEXT: "col": 37, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -221,18 +226,18 @@ int main() { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "ParmVarDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 243, // CHECK-NEXT: "col": 27, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 238, // CHECK-NEXT: "col": 22, // CHECK-NEXT: "tokLen": 5 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 238, // CHECK-NEXT: "col": 22, // CHECK-NEXT: "tokLen": 5 // CHECK-NEXT: } @@ -245,18 +250,18 @@ int main() { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "ParmVarDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 249, // CHECK-NEXT: "col": 33, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 245, // CHECK-NEXT: "col": 29, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 251, // CHECK-NEXT: "col": 35, // CHECK-NEXT: "tokLen": 2 // CHECK-NEXT: } @@ -271,12 +276,12 @@ int main() { // CHECK-NEXT: "kind": "IntegerLiteral", // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 251, // CHECK-NEXT: "col": 35, // CHECK-NEXT: "tokLen": 2 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 251, // CHECK-NEXT: "col": 35, // CHECK-NEXT: "tokLen": 2 // CHECK-NEXT: } @@ -296,7 +301,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "CXXMethodDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 271, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 10, // CHECK-NEXT: "col": 16, @@ -304,12 +309,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 258, // CHECK-NEXT: "col": 3, // CHECK-NEXT: "tokLen": 7 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 281, // CHECK-NEXT: "col": 26, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -327,7 +332,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "CXXMethodDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 343, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 14, // CHECK-NEXT: "col": 8, @@ -335,12 +340,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 338, // CHECK-NEXT: "col": 3, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 367, // CHECK-NEXT: "col": 32, // CHECK-NEXT: "tokLen": 8 // CHECK-NEXT: } @@ -355,18 +360,18 @@ int main() { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "ParmVarDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 354, // CHECK-NEXT: "col": 19, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 349, // CHECK-NEXT: "col": 14, // CHECK-NEXT: "tokLen": 5 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 349, // CHECK-NEXT: "col": 14, // CHECK-NEXT: "tokLen": 5 // CHECK-NEXT: } @@ -379,18 +384,18 @@ int main() { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "ParmVarDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 360, // CHECK-NEXT: "col": 25, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 356, // CHECK-NEXT: "col": 21, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 362, // CHECK-NEXT: "col": 27, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: } @@ -405,12 +410,12 @@ int main() { // CHECK-NEXT: "kind": "IntegerLiteral", // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 362, // CHECK-NEXT: "col": 27, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 362, // CHECK-NEXT: "col": 27, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: } @@ -428,12 +433,12 @@ int main() { // CHECK-NEXT: "kind": "OverrideAttr", // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 367, // CHECK-NEXT: "col": 32, // CHECK-NEXT: "tokLen": 8 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 367, // CHECK-NEXT: "col": 32, // CHECK-NEXT: "tokLen": 8 // CHECK-NEXT: } @@ -446,7 +451,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "CXXMethodDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 399, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 18, // CHECK-NEXT: "col": 8, @@ -454,12 +459,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 394, // CHECK-NEXT: "col": 3, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 405, // CHECK-NEXT: "col": 14, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -475,7 +480,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "CXXMethodDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 419, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 20, // CHECK-NEXT: "col": 9, @@ -483,12 +488,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 411, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 428, // CHECK-NEXT: "col": 18, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -506,12 +511,12 @@ int main() { // CHECK-NEXT: "kind": "CompoundStmt", // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 427, // CHECK-NEXT: "col": 17, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 428, // CHECK-NEXT: "col": 18, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -524,7 +529,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 446, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 22, // CHECK-NEXT: "col": 6, @@ -532,12 +537,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 441, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 452, // CHECK-NEXT: "col": 12, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -554,7 +559,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 460, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 23, // CHECK-NEXT: "col": 6, @@ -562,12 +567,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 455, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 470, // CHECK-NEXT: "col": 16, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -583,7 +588,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 478, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 24, // CHECK-NEXT: "col": 6, @@ -591,12 +596,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 473, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 496, // CHECK-NEXT: "col": 24, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -611,18 +616,18 @@ int main() { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "ParmVarDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 488, // CHECK-NEXT: "col": 16, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 484, // CHECK-NEXT: "col": 12, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 488, // CHECK-NEXT: "col": 16, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -636,18 +641,18 @@ int main() { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "ParmVarDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 495, // CHECK-NEXT: "col": 23, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 491, // CHECK-NEXT: "col": 19, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 495, // CHECK-NEXT: "col": 23, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -664,7 +669,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 504, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 25, // CHECK-NEXT: "col": 6, @@ -672,12 +677,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 499, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 527, // CHECK-NEXT: "col": 29, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -692,18 +697,18 @@ int main() { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "ParmVarDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 514, // CHECK-NEXT: "col": 16, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 510, // CHECK-NEXT: "col": 12, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 514, // CHECK-NEXT: "col": 16, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -717,18 +722,18 @@ int main() { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "ParmVarDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 521, // CHECK-NEXT: "col": 23, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 517, // CHECK-NEXT: "col": 19, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 525, // CHECK-NEXT: "col": 27, // CHECK-NEXT: "tokLen": 2 // CHECK-NEXT: } @@ -744,12 +749,12 @@ int main() { // CHECK-NEXT: "kind": "IntegerLiteral", // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 525, // CHECK-NEXT: "col": 27, // CHECK-NEXT: "tokLen": 2 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 525, // CHECK-NEXT: "col": 27, // CHECK-NEXT: "tokLen": 2 // CHECK-NEXT: } @@ -769,7 +774,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 545, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 26, // CHECK-NEXT: "col": 16, @@ -777,12 +782,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 530, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 9 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 555, // CHECK-NEXT: "col": 26, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -799,7 +804,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 570, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 27, // CHECK-NEXT: "col": 13, @@ -807,12 +812,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 558, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 6 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 580, // CHECK-NEXT: "col": 23, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -829,7 +834,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 595, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 28, // CHECK-NEXT: "col": 13, @@ -837,12 +842,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 583, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 6 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 605, // CHECK-NEXT: "col": 23, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -859,7 +864,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 620, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 29, // CHECK-NEXT: "col": 13, @@ -867,12 +872,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 608, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 6 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 630, // CHECK-NEXT: "col": 23, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -889,7 +894,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 638, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 30, // CHECK-NEXT: "col": 6, @@ -897,12 +902,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 633, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 650, // CHECK-NEXT: "col": 18, // CHECK-NEXT: "tokLen": 8 // CHECK-NEXT: } @@ -918,7 +923,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 665, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 31, // CHECK-NEXT: "col": 6, @@ -926,12 +931,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 660, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 692, // CHECK-NEXT: "col": 33, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -947,7 +952,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 700, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 32, // CHECK-NEXT: "col": 6, @@ -955,12 +960,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 695, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 723, // CHECK-NEXT: "col": 29, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -976,7 +981,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionTemplateDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 751, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 35, // CHECK-NEXT: "col": 3, @@ -984,13 +989,13 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 727, // CHECK-NEXT: "line": 34, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 8 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 760, // CHECK-NEXT: "line": 35, // CHECK-NEXT: "col": 12, // CHECK-NEXT: "tokLen": 1 @@ -1002,19 +1007,19 @@ int main() { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "TemplateTypeParmDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 746, // CHECK-NEXT: "line": 34, // CHECK-NEXT: "col": 20, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 737, // CHECK-NEXT: "col": 11, // CHECK-NEXT: "tokLen": 8 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 746, // CHECK-NEXT: "col": 20, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -1029,19 +1034,19 @@ int main() { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 751, // CHECK-NEXT: "line": 35, // CHECK-NEXT: "col": 3, // CHECK-NEXT: "tokLen": 6 // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 749, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 760, // CHECK-NEXT: "col": 12, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -1055,18 +1060,18 @@ int main() { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "ParmVarDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 760, // CHECK-NEXT: "col": 12, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 758, // CHECK-NEXT: "col": 10, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 759, // CHECK-NEXT: "col": 11, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -1084,7 +1089,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 769, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 37, // CHECK-NEXT: "col": 6, @@ -1092,12 +1097,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 764, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 782, // CHECK-NEXT: "col": 19, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -1112,18 +1117,18 @@ int main() { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "ParmVarDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 779, // CHECK-NEXT: "col": 16, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 776, // CHECK-NEXT: "col": 13, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 776, // CHECK-NEXT: "col": 13, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: } @@ -1137,12 +1142,12 @@ int main() { // CHECK-NEXT: "kind": "CompoundStmt", // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 781, // CHECK-NEXT: "col": 18, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 782, // CHECK-NEXT: "col": 19, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -1155,7 +1160,7 @@ int main() { // CHECK-NOT: {{^}}Dumping // CHECK: "kind": "FunctionDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 789, // CHECK-NEXT: "file": "{{.*}}", // CHECK-NEXT: "line": 38, // CHECK-NEXT: "col": 6, @@ -1163,12 +1168,12 @@ int main() { // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 784, // CHECK-NEXT: "col": 1, // CHECK-NEXT: "tokLen": 4 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 807, // CHECK-NEXT: "col": 24, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -1184,18 +1189,18 @@ int main() { // CHECK-NEXT: "id": "0x{{.*}}", // CHECK-NEXT: "kind": "ParmVarDecl", // CHECK-NEXT: "loc": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 799, // CHECK-NEXT: "col": 16, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 796, // CHECK-NEXT: "col": 13, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 796, // CHECK-NEXT: "col": 13, // CHECK-NEXT: "tokLen": 3 // CHECK-NEXT: } @@ -1209,12 +1214,12 @@ int main() { // CHECK-NEXT: "kind": "CompoundStmt", // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 806, // CHECK-NEXT: "col": 23, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: }, // CHECK-NEXT: "end": { -// CHECK-NEXT: "offset": {{[0-9]+}}, +// CHECK-NEXT: "offset": 807, // CHECK-NEXT: "col": 24, // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } @@ -1222,3 +1227,189 @@ int main() { // CHECK-NEXT: } // CHECK-NEXT: ] // CHECK-NEXT: } + + +// CHECK-NOT: {{^}}Dumping +// CHECK: "kind": "ClassTemplateDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 905, +// CHECK-NEXT: "file": "{{.*}}", +// CHECK-NEXT: "line": 45, +// CHECK-NEXT: "col": 8, +// CHECK-NEXT: "tokLen": 11 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 872, +// CHECK-NEXT: "line": 44, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 8 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 937, +// CHECK-NEXT: "line": 47, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "name": "TestFriends", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TemplateTypeParmDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 894, +// CHECK-NEXT: "line": 44, +// CHECK-NEXT: "col": 23, +// CHECK-NEXT: "tokLen": 2 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 882, +// CHECK-NEXT: "col": 11, +// CHECK-NEXT: "tokLen": 8 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 894, +// CHECK-NEXT: "col": 23, +// CHECK-NEXT: "tokLen": 2 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "isReferenced": true, +// CHECK-NEXT: "name": "Ts", +// CHECK-NEXT: "tagUsed": "typename", +// CHECK-NEXT: "depth": 0, +// CHECK-NEXT: "index": 0, +// CHECK-NEXT: "isParameterPack": true +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "CXXRecordDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 905, +// CHECK-NEXT: "line": 45, +// CHECK-NEXT: "col": 8, +// CHECK-NEXT: "tokLen": 11 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 898, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 6 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 937, +// CHECK-NEXT: "line": 47, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "name": "TestFriends", +// CHECK-NEXT: "tagUsed": "struct", +// CHECK-NEXT: "completeDefinition": true, +// CHECK-NEXT: "definitionData": { +// CHECK-NEXT: "canConstDefaultInit": true, +// CHECK-NEXT: "copyAssign": { +// CHECK-NEXT: "hasConstParam": true, +// CHECK-NEXT: "implicitHasConstParam": true, +// CHECK-NEXT: "needsImplicit": true, +// CHECK-NEXT: "simple": true, +// CHECK-NEXT: "trivial": true +// CHECK-NEXT: }, +// CHECK-NEXT: "copyCtor": { +// CHECK-NEXT: "hasConstParam": true, +// CHECK-NEXT: "implicitHasConstParam": true, +// CHECK-NEXT: "needsImplicit": true, +// CHECK-NEXT: "simple": true, +// CHECK-NEXT: "trivial": true +// CHECK-NEXT: }, +// CHECK-NEXT: "defaultCtor": { +// CHECK-NEXT: "defaultedIsConstexpr": true, +// CHECK-NEXT: "exists": true, +// CHECK-NEXT: "isConstexpr": true, +// CHECK-NEXT: "needsImplicit": true, +// CHECK-NEXT: "trivial": true +// CHECK-NEXT: }, +// CHECK-NEXT: "dtor": { +// CHECK-NEXT: "irrelevant": true, +// CHECK-NEXT: "needsImplicit": true, +// CHECK-NEXT: "simple": true, +// CHECK-NEXT: "trivial": true +// CHECK-NEXT: }, +// CHECK-NEXT: "hasConstexprNonCopyMoveConstructor": true, +// CHECK-NEXT: "isAggregate": true, +// CHECK-NEXT: "isEmpty": true, +// CHECK-NEXT: "isLiteral": true, +// CHECK-NEXT: "isPOD": true, +// CHECK-NEXT: "isStandardLayout": true, +// CHECK-NEXT: "isTrivial": true, +// CHECK-NEXT: "isTriviallyCopyable": true, +// CHECK-NEXT: "moveAssign": { +// CHECK-NEXT: "exists": true, +// CHECK-NEXT: "needsImplicit": true, +// CHECK-NEXT: "simple": true, +// CHECK-NEXT: "trivial": true +// CHECK-NEXT: }, +// CHECK-NEXT: "moveCtor": { +// CHECK-NEXT: "exists": true, +// CHECK-NEXT: "needsImplicit": true, +// CHECK-NEXT: "simple": true, +// CHECK-NEXT: "trivial": true +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "CXXRecordDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 905, +// CHECK-NEXT: "line": 45, +// CHECK-NEXT: "col": 8, +// CHECK-NEXT: "tokLen": 11 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 898, +// CHECK-NEXT: "col": 1, +// CHECK-NEXT: "tokLen": 6 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 905, +// CHECK-NEXT: "col": 8, +// CHECK-NEXT: "tokLen": 11 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "isImplicit": true, +// CHECK-NEXT: "name": "TestFriends", +// CHECK-NEXT: "tagUsed": "struct" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "FriendDecl", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 930, +// CHECK-NEXT: "line": 46, +// CHECK-NEXT: "col": 12, +// CHECK-NEXT: "tokLen": 2 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 923, +// CHECK-NEXT: "col": 5, +// CHECK-NEXT: "tokLen": 6 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 932, +// CHECK-NEXT: "col": 14, +// CHECK-NEXT: "tokLen": 3 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "Ts" +// CHECK-NEXT: }, +// CHECK-NEXT: "isPackExpansion": true +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } diff --git a/clang/test/AST/cxx2c-variadic-friends.cpp b/clang/test/AST/cxx2c-variadic-friends.cpp new file mode 100644 index 0000000000000..fc84e7346fe03 --- /dev/null +++ b/clang/test/AST/cxx2c-variadic-friends.cpp @@ -0,0 +1,81 @@ +// RUN: %clang_cc1 -fsyntax-only -ast-dump -std=c++2c %s | FileCheck %s +// RUN: %clang_cc1 -ast-print -std=c++2c %s | FileCheck %s --check-prefix=PRINT +// RUN: %clang_cc1 -emit-pch -std=c++2c -o %t %s +// RUN: %clang_cc1 -x c++ -std=c++2c -include-pch %t -ast-dump-all /dev/null + +struct S; +template struct TS; // #template + +// CHECK-LABEL: CXXRecordDecl {{.*}} struct Friends +// PRINT-LABEL: struct Friends { +struct Friends { + // CHECK: FriendDecl {{.*}} 'int' + // CHECK-NEXT: FriendDecl {{.*}} 'long' + // PRINT-NEXT: friend int; + // PRINT-NEXT: friend long; + friend int, long; + + // CHECK-NEXT: FriendDecl {{.*}} 'int' + // CHECK-NEXT: FriendDecl {{.*}} 'long' + // CHECK-NEXT: FriendDecl {{.*}} 'char' + // PRINT-NEXT: friend int; + // PRINT-NEXT: friend long; + // PRINT-NEXT: friend char; + friend int, long, char; + + // CHECK-NEXT: FriendDecl {{.*}} 'S' + // PRINT-NEXT: friend S; + friend S; + + // CHECK-NEXT: FriendDecl {{.*}} 'S' + // CHECK-NEXT: FriendDecl {{.*}} 'S' + // CHECK-NEXT: FriendDecl {{.*}} 'S' + // PRINT-NEXT: friend S; + // PRINT-NEXT: friend S; + // PRINT-NEXT: friend S; + friend S, S, S; + + // CHECK-NEXT: FriendDecl + // CHECK-NEXT: ClassTemplateDecl {{.*}} friend TS + // PRINT-NEXT: friend template struct TS; + template friend struct TS; +}; + +namespace specialisations { +template +struct C { + template struct Nested; +}; + +struct N { + template class C; +}; + +// CHECK-LABEL: ClassTemplateDecl {{.*}} Variadic +// PRINT-LABEL: template struct Variadic { +template struct Variadic { + // CHECK: FriendDecl {{.*}} 'Pack'... + // CHECK-NEXT: FriendDecl {{.*}} 'long' + // CHECK-NEXT: FriendDecl {{.*}} 'Pack'... + // PRINT-NEXT: friend Pack...; + // PRINT-NEXT: friend long; + // PRINT-NEXT: friend Pack...; + friend Pack..., long, Pack...; + + // CHECK-NEXT: FriendDecl {{.*}} 'TS'... + // PRINT-NEXT: friend TS...; + friend TS...; +}; + +// CHECK-LABEL: ClassTemplateDecl {{.*}} S2 +// PRINT-LABEL: template struct S2 { +template struct S2 { + // CHECK: FriendDecl {{.*}} 'class C':'C'... + // PRINT-NEXT: friend class C...; + friend class C...; + + // CHECK-NEXT: FriendDecl {{.*}} 'class N::C':'C'... + // PRINT-NEXT: friend class N::C... + friend class N::C...; +}; +} diff --git a/clang/test/CXX/drs/cwg29xx.cpp b/clang/test/CXX/drs/cwg29xx.cpp new file mode 100644 index 0000000000000..8cac9f283980b --- /dev/null +++ b/clang/test/CXX/drs/cwg29xx.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -std=c++98 -pedantic-errors -verify=expected,cxx98 %s +// RUN: %clang_cc1 -std=c++11 -pedantic-errors -verify=expected %s +// RUN: %clang_cc1 -std=c++14 -pedantic-errors -verify=expected %s +// RUN: %clang_cc1 -std=c++17 -pedantic-errors -verify=expected %s +// RUN: %clang_cc1 -std=c++20 -pedantic-errors -verify=expected %s +// RUN: %clang_cc1 -std=c++23 -pedantic-errors -verify=expected %s +// RUN: %clang_cc1 -std=c++2c -pedantic-errors -verify=expected %s + +namespace cwg2917 { // cwg2917: 20 open 2024-07-30 +template +class Foo; + +template // cxx98-error {{variadic templates are a C++11 extension}} +struct C { + struct Nested { }; +}; + +struct S { + template + friend class Foo, int; // expected-error {{a friend declaration that befriends a template must contain exactly one type-specifier}} + + template // cxx98-error {{variadic templates are a C++11 extension}} + friend class C::Nested...; // expected-error {{friend declaration expands pack 'Ts' that is declared it its own template parameter list}} +}; +} // namespace cwg2917 diff --git a/clang/test/Lexer/cxx-features.cpp b/clang/test/Lexer/cxx-features.cpp index 08b732132228b..1c51013ca06f7 100644 --- a/clang/test/Lexer/cxx-features.cpp +++ b/clang/test/Lexer/cxx-features.cpp @@ -34,6 +34,10 @@ // --- C++26 features --- +#if check(variadic_friend, 202403, 202403, 202403, 202403, 202403, 202403, 202403) +#error "wrong value for __cpp_variadic_friend" +#endif + #if check(deleted_function, 202403, 202403, 202403, 202403, 202403, 202403, 202403) #error "wrong value for __cpp_deleted_function" #endif diff --git a/clang/test/Parser/cxx2c-variadic-friends-ext-diags.cpp b/clang/test/Parser/cxx2c-variadic-friends-ext-diags.cpp new file mode 100644 index 0000000000000..ffcc97ffd6352 --- /dev/null +++ b/clang/test/Parser/cxx2c-variadic-friends-ext-diags.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -std=c++2c -verify=compat -fsyntax-only -Wpre-c++26-compat %s +// RUN: %clang_cc1 -std=c++11 -verify=pre2c -fsyntax-only -Wc++26-extensions %s + +struct S { + friend int, long, char; // compat-warning {{variadic 'friend' declarations are incompatible with C++ standards before C++2c}} \ + // pre2c-warning {{variadic 'friend' declarations are a C++2c extension}} +}; + +template +struct TS { + friend Types...; // compat-warning {{variadic 'friend' declarations are incompatible with C++ standards before C++2c}} \ + // pre2c-warning {{variadic 'friend' declarations are a C++2c extension}} + + friend int, Types..., Types...; // compat-warning {{variadic 'friend' declarations are incompatible with C++ standards before C++2c}} \ + // pre2c-warning {{variadic 'friend' declarations are a C++2c extension}} +}; diff --git a/clang/test/Parser/cxx2c-variadic-friends.cpp b/clang/test/Parser/cxx2c-variadic-friends.cpp new file mode 100644 index 0000000000000..b7da3e6110481 --- /dev/null +++ b/clang/test/Parser/cxx2c-variadic-friends.cpp @@ -0,0 +1,91 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2c %s + +template struct TS; // #template + +struct Errors { + friend int, int; + friend int, long, char; + + // We simply diagnose and ignore the '...' here. + friend float...; // expected-error {{pack expansion does not contain any unexpanded parameter packs}} + + friend short..., unsigned, unsigned short...; // expected-error 2 {{pack expansion does not contain any unexpanded parameter packs}} + + template + friend struct TS, int; // expected-error {{a friend declaration that befriends a template must contain exactly one type-specifier}} + + double friend; // expected-error {{'friend' must appear first in a non-function declaration}} + double friend, double; // expected-error {{expected member name or ';' after declaration specifiers}} +}; + +template +struct C { template class Nested; }; + +template +struct D { template class Nested; }; + +template +struct E { template class Nested; }; + +template // expected-note {{template parameter is declared here}} +struct VS { + friend Ts...; + + friend class Ts...; // expected-error {{declaration of 'Ts' shadows template parameter}} + // expected-error@-1 {{pack expansion does not contain any unexpanded parameter packs}} + + // TODO: Fix-it hint to insert '...'. + friend Ts; // expected-error {{friend declaration contains unexpanded parameter pack}} + + template + friend Us...; // expected-error {{friend type templates must use an elaborated type}} + + template // expected-note {{is declared here}} + friend class Us...; // expected-error {{declaration of 'Us' shadows template parameter}} + + template + friend class C::template Nested...; // expected-error {{cannot specialize a dependent template}} + + template + friend class C::template Nested...; // expected-error {{cannot specialize a dependent template}} + + // Nonsense (see CWG 2917). + template + friend class C::Nested...; // expected-error {{friend declaration expands pack 'Us' that is declared it its own template parameter list}} + + template + friend class E::Nested...; // expected-error {{friend declaration expands pack 'Bs' that is declared it its own template parameter list}} + + // FIXME: Both of these should be valid, but we can't handle these at + // the moment because the NNS is dependent. + template + friend class TS::Nested...; // expected-warning {{dependent nested name specifier 'TS::' for friend template declaration is not supported; ignoring this friend declaration}} + + template + friend class D::Nested...; // expected-warning {{dependent nested name specifier 'D::' for friend class declaration is not supported; turning off access control for 'VS'}} +}; + +namespace length_mismatch { +struct A { + template + struct Nested { + struct Foo{}; + }; +}; +template +struct S { + template + struct T { + // expected-error@+2 {{pack expansion contains parameter packs 'Ts' and 'Us' that have different lengths (1 vs. 2)}} + // expected-error@+1 {{pack expansion contains parameter packs 'Ts' and 'Us' that have different lengths (2 vs. 1)}} + friend class Ts::template Nested::Foo...; + }; +}; + +void f() { + S::T s; + S::T s2; + S::T s3; // expected-note {{in instantiation of}} + S::T s4; // expected-note {{in instantiation of}} +} +} diff --git a/clang/test/SemaCXX/cxx2c-variadic-friends.cpp b/clang/test/SemaCXX/cxx2c-variadic-friends.cpp new file mode 100644 index 0000000000000..a4d7c8078338d --- /dev/null +++ b/clang/test/SemaCXX/cxx2c-variadic-friends.cpp @@ -0,0 +1,156 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2c %s + +struct A; +struct B; +struct C; + +struct S {}; +template struct TS {}; + +template +class X { + friend Pack...; + static void f() { } // expected-note {{declared private here}} +}; + +class Y { + friend A, B, C; + static void g() { } // expected-note {{declared private here}} +}; + +struct A { + A() { + X::f(); + Y::g(); + }; +}; + +struct B { + B() { + X::f(); + Y::g(); + }; +}; + +struct C { + C() { + X::f(); + Y::g(); + }; +}; + +struct D { + D() { + X::f(); // expected-error {{'f' is a private member of 'X'}} + Y::g(); // expected-error {{'g' is a private member of 'Y'}} + }; +}; + +void f1() { + A a; + B b; + C c; + D d; +} + +template +struct Z { + template