[clang] 2b0a8fc - [Clang] Implement C++26’s P2893R3 ‘Variadic friends’ (#101448)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 15 12:16:35 PDT 2024
Author: Sirraide
Date: 2024-08-15T21:16:30+02:00
New Revision: 2b0a8fcf702fb63fca8ec6e11dca35baf70f058d
URL: https://github.com/llvm/llvm-project/commit/2b0a8fcf702fb63fca8ec6e11dca35baf70f058d
DIFF: https://github.com/llvm/llvm-project/commit/2b0a8fcf702fb63fca8ec6e11dca35baf70f058d.diff
LOG: [Clang] Implement C++26’s P2893R3 ‘Variadic friends’ (#101448)
Implement P2893R3 ‘Variadic friends’ for C++26.
This closes #98587.
Co-authored-by: Younan Zhang <zyn7109 at gmail.com>
Added:
clang/test/AST/cxx2c-variadic-friends.cpp
clang/test/CXX/drs/cwg29xx.cpp
clang/test/Parser/cxx2c-variadic-friends-ext-diags.cpp
clang/test/Parser/cxx2c-variadic-friends.cpp
clang/test/SemaCXX/cxx2c-variadic-friends.cpp
Modified:
clang/docs/LanguageExtensions.rst
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/DeclFriend.h
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/DeclFriend.cpp
clang/lib/AST/DeclPrinter.cpp
clang/lib/AST/JSONNodeDumper.cpp
clang/lib/AST/ODRHash.cpp
clang/lib/AST/TextNodeDumper.cpp
clang/lib/Frontend/InitPreprocessor.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/AST/ast-dump-funcs-json.cpp
clang/test/Lexer/cxx-features.cpp
clang/www/cxx_dr_status.html
clang/www/cxx_status.html
Removed:
################################################################################
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 4679dbb68b25e1..114e742f3561b7 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 68cf79928bda02..14f1eecc5748ed 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 <https://wg21.link/p2985r0>`_
+- Implemented `P2893R3 Variadic Friends <https://wg21.link/P2893>`_
+
Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/DeclFriend.h b/clang/include/clang/AST/DeclFriend.h
index 9789282f351a55..095f14a81fd574 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<TemplateParameterList *> 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<TemplateParameterList *>()[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<TemplateParameterList *> 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<TemplateParameterList *>()[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<FunctionDecl>(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<TemplateParameterList *>()[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 12aab09f285567..62a97b36737e72 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<CXXPre26Compat>;
+def ext_variadic_friends : ExtWarn<
+ "variadic 'friend' declarations are a C++2c extension">, InGroup<CXX26>;
+def warn_cxx23_variadic_friends : Warning<
+ "variadic 'friend' declarations are incompatible with C++ standards before C++2c">,
+ DefaultIgnore, InGroup<CXXPre26Compat>;
+
// 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 461eeb19f65e4a..8a92973236ddbd 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<MicrosoftUnqualifiedFriend>;
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 a025ff6fc13f36..88e82dca007b8b 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 \<class T> friend class A<int>::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 198bc34a9f031b..3bc0a647ebf94f 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 04b9b93699f36c..8b285bfce8d522 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<TemplateParameterList *> FriendTypeTPLists) {
+FriendDecl *
+FriendDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ FriendUnion Friend, SourceLocation FriendL,
+ SourceLocation EllipsisLoc,
+ ArrayRef<TemplateParameterList *> FriendTypeTPLists) {
#ifndef NDEBUG
if (Friend.is<NamedDecl *>()) {
const auto *D = Friend.get<NamedDecl*>();
@@ -56,8 +56,8 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
std::size_t Extra =
FriendDecl::additionalSizeToAlloc<TemplateParameterList *>(
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<CXXRecordDecl>(DC)->pushFriendDecl(FD);
return FD;
}
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 26773a69ab9acf..07be813abd8adc 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<FunctionDecl>(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 f8f80c8c251575..565f1e05710c87 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 fbfe92318dc5ee..b748093831e3f5 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -461,6 +461,7 @@ class ODRDeclVisitor : public ConstDeclVisitor<ODRDeclVisitor> {
} 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 d50d4c7028c697..2c962253c8bea4 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 8e62461d8a1818..4f2856dd2247f8 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 d45a738fe4c596..18c5fe6056b472 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 <typename>
+ // 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<Decl *> 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 641b180527da55..83a652691e2e03 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 9ca91a2def39f5..e05595e565d54a 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<TypeSpecTypeLoc>().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<UnexpandedParameterPack, 1> Unexpanded;
+ collectUnexpandedParameterPacks(QualifierLoc, Unexpanded);
+ unsigned FriendDeclDepth = TempParamLists.front()->getDepth();
+ for (UnexpandedParameterPack &U : Unexpanded) {
+ if (getDepthAndIndex(U).first >= FriendDeclDepth) {
+ auto *ND = U.first.dyn_cast<NamedDecl *>();
+ if (!ND)
+ ND = U.first.get<const TemplateTypeParmType *>()->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 T> class A<T>::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 f93cd113988ae4..14ca29f1bc3f1a 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<UnexpandedParameterPack, 2> Unexpanded;
+ SemaRef.collectUnexpandedParameterPacks(Ty->getTypeLoc(), Unexpanded);
+ assert(!Unexpanded.empty() && "Pack expansion without packs");
+
+ bool ShouldExpand = true;
+ bool RetainExpansion = false;
+ std::optional<unsigned> 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<FriendDecl *> 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 a9199f7e50f5dc..ef160228933c59 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 8a4ca54349e38f..555f6325da646b 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 041d98f2713d32..957df5cea6ec53 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 <typename ...Ts>
+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 00000000000000..fc84e7346fe036
--- /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 <typename> 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 <typename> struct TS;
+ template <typename> friend struct TS;
+};
+
+namespace specialisations {
+template<class T>
+struct C {
+ template<class U> struct Nested;
+};
+
+struct N {
+ template<class U> class C;
+};
+
+// CHECK-LABEL: ClassTemplateDecl {{.*}} Variadic
+// PRINT-LABEL: template <typename ...Pack> struct Variadic {
+template <typename ...Pack> 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<Pack>'...
+ // PRINT-NEXT: friend TS<Pack>...;
+ friend TS<Pack>...;
+};
+
+// CHECK-LABEL: ClassTemplateDecl {{.*}} S2
+// PRINT-LABEL: template <class ...Ts> struct S2 {
+template<class ...Ts> struct S2 {
+ // CHECK: FriendDecl {{.*}} 'class C<Ts>':'C<Ts>'...
+ // PRINT-NEXT: friend class C<Ts>...;
+ friend class C<Ts>...;
+
+ // CHECK-NEXT: FriendDecl {{.*}} 'class N::C<Ts>':'C<Ts>'...
+ // PRINT-NEXT: friend class N::C<Ts>...
+ friend class N::C<Ts>...;
+};
+}
diff --git a/clang/test/CXX/drs/cwg29xx.cpp b/clang/test/CXX/drs/cwg29xx.cpp
new file mode 100644
index 00000000000000..8cac9f283980b6
--- /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 <typename>
+class Foo;
+
+template<class ...> // cxx98-error {{variadic templates are a C++11 extension}}
+struct C {
+ struct Nested { };
+};
+
+struct S {
+ template <typename>
+ friend class Foo, int; // expected-error {{a friend declaration that befriends a template must contain exactly one type-specifier}}
+
+ template <typename ...Ts> // cxx98-error {{variadic templates are a C++11 extension}}
+ friend class C<Ts>::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 08b732132228ba..1c51013ca06f77 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 00000000000000..ffcc97ffd63529
--- /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 <typename ...Types>
+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 00000000000000..b7da3e61104812
--- /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 <typename> 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 <typename>
+ 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 <typename>
+struct C { template<class T> class Nested; };
+
+template <typename, typename>
+struct D { template<class T> class Nested; };
+
+template <bool>
+struct E { template<class T> class Nested; };
+
+template<class... Ts> // expected-note {{template parameter is declared here}}
+struct VS {
+ friend Ts...;
+
+ friend class Ts...; // expected-error {{declaration of 'Ts' shadows template parameter}}
+ // expected-error at -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<class... Us>
+ friend Us...; // expected-error {{friend type templates must use an elaborated type}}
+
+ template<class... Us> // expected-note {{is declared here}}
+ friend class Us...; // expected-error {{declaration of 'Us' shadows template parameter}}
+
+ template<class U>
+ friend class C<Ts>::template Nested<U>...; // expected-error {{cannot specialize a dependent template}}
+
+ template<class... Us>
+ friend class C<Ts...>::template Nested<Us>...; // expected-error {{cannot specialize a dependent template}}
+
+ // Nonsense (see CWG 2917).
+ template<class... Us>
+ friend class C<Us>::Nested...; // expected-error {{friend declaration expands pack 'Us' that is declared it its own template parameter list}}
+
+ template<bool... Bs>
+ friend class E<Bs>::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<class ...T>
+ friend class TS<Ts>::Nested...; // expected-warning {{dependent nested name specifier 'TS<Ts>::' for friend template declaration is not supported; ignoring this friend declaration}}
+
+ template<class T>
+ friend class D<T, Ts>::Nested...; // expected-warning {{dependent nested name specifier 'D<T, Ts>::' for friend class declaration is not supported; turning off access control for 'VS'}}
+};
+
+namespace length_mismatch {
+struct A {
+ template <typename...>
+ struct Nested {
+ struct Foo{};
+ };
+};
+template <typename ...Ts>
+struct S {
+ template <typename ...Us>
+ struct T {
+ // expected-error at +2 {{pack expansion contains parameter packs 'Ts' and 'Us' that have
diff erent lengths (1 vs. 2)}}
+ // expected-error at +1 {{pack expansion contains parameter packs 'Ts' and 'Us' that have
diff erent lengths (2 vs. 1)}}
+ friend class Ts::template Nested<Us>::Foo...;
+ };
+};
+
+void f() {
+ S<A>::T<int> s;
+ S<A, A>::T<int, long> s2;
+ S<A>::T<int, long> s3; // expected-note {{in instantiation of}}
+ S<A, A>::T<int> 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 00000000000000..a4d7c8078338d2
--- /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 <typename> struct TS {};
+
+template <typename ...Pack>
+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<A>::f();
+ Y::g();
+ };
+};
+
+struct B {
+ B() {
+ X<B, C>::f();
+ Y::g();
+ };
+};
+
+struct C {
+ C() {
+ X<A, B, C>::f();
+ Y::g();
+ };
+};
+
+struct D {
+ D() {
+ X<A, B, C>::f(); // expected-error {{'f' is a private member of 'X<A, B, C>'}}
+ Y::g(); // expected-error {{'g' is a private member of 'Y'}}
+ };
+};
+
+void f1() {
+ A a;
+ B b;
+ C c;
+ D d;
+}
+
+template <typename ...Pack>
+struct Z {
+ template <template <typename> class Template>
+ struct Inner {
+ friend Template<Pack>...;
+ };
+};
+
+void f2() {
+ Z<int, long, char> z;
+ Z<int, long, char>::Inner<TS> inner;
+}
+
+namespace p2893r3_examples {
+template<class... Ts>
+class Passkey {
+ friend Ts...;
+ Passkey() {} // expected-note {{declared private here}}
+};
+
+class Foo;
+class Bar;
+class Baz;
+
+class C {
+public:
+ void f(Passkey<Foo, Bar, Baz>);
+};
+
+class Foo {
+ Foo() { C c; c.f({}); }
+};
+
+class Bar {
+ Bar() { C c; c.f({}); }
+};
+
+class Baz {
+ Baz() { C c; c.f({}); }
+};
+
+class Quux {
+ Quux() { C c; c.f({}); } // expected-error {{calling a private constructor of class 'p2893r3_examples::Passkey<p2893r3_examples::Foo, p2893r3_examples::Bar, p2893r3_examples::Baz>'}}
+};
+
+template<class Derived, class MsgT>
+struct Receiver {
+ void receive(MsgT) {
+ static_cast<Derived*>(this)->private_ += 1;
+ }
+};
+
+template<class... MsgTs>
+struct Dispatcher : Receiver<Dispatcher<MsgTs...>, MsgTs>... {
+ using Receiver<Dispatcher, MsgTs>::receive...;
+ friend Receiver<Dispatcher, MsgTs>...;
+
+private:
+ int private_;
+};
+
+void f() {
+ Dispatcher<int, float> d;
+ d.receive(0);
+ d.receive(0.0f);
+}
+} // namespace p2893r3_examples
+
+namespace p2893r3_note {
+template <class... Ts> class R {
+ friend Ts...;
+};
+
+template <class... Ts, class... Us>
+class R<R<Ts...>, R<Us...>> {
+ friend Ts::Nested..., Us...;
+};
+
+struct E { struct Nested; };
+R<R<E>, R<C, int>> rr;
+} // namespace p2893r3_note
+
+namespace template_template {
+template <typename U, template <typename> typename... Friend>
+class S {
+ friend class Friend<U>...;
+ static constexpr int a = 42;
+};
+
+template <typename U>
+struct T {
+ static_assert(S<U, T>::a == 42);
+ static_assert(S<U, T>::a == 43); // expected-error {{static assertion failed due to requirement 'S<int, template_template::T>::a == 43'}} \
+ // expected-note {{expression evaluates to '42 == 43'}}
+};
+
+void f() {
+ T<int> t; // expected-note {{in instantiation of}}
+}
+}
+
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 9b0de55483d275..34ca6f76bb2ce6 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -17318,7 +17318,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2917.html">2917</a></td>
<td>open</td>
<td>Disallow multiple <I>friend-type-specifier</I>s for a friend template</td>
- <td align="center">Not resolved</td>
+ <td title="Clang 20 implements 2024-07-30 resolution" align="center">Not Resolved*</td>
</tr>
<tr class="open" id="2918">
<td><a href="https://cplusplus.github.io/CWG/issues/2918.html">2918</a></td>
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index a6ded8be3ae9e5..faee8b578b6242 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -202,7 +202,7 @@ <h2 id="cxx26">C++2c implementation status</h2>
<tr>
<td>Variadic friends</td>
<td><a href="https://wg21.link/P2893R3">P2893R3</a></td>
- <td class="none" align="center">No</td>
+ <td class="unreleased" align="center">Clang 20</td>
</tr>
<!-- Summer 2024 papers (St Louis) -->
<tr>
More information about the cfe-commits
mailing list