[llvm-branch-commits] [clang-tools-extra] 57a04e1 - Revert "[Clang] Support friend declarations with a dependent nested-name-spec…"
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Aug 16 00:53:20 PDT 2026
Author: Oleksandr Tarasiuk
Date: 2026-08-16T10:53:15+03:00
New Revision: 57a04e139f56b4f30b9207b50b936194c98e1b8a
URL: https://github.com/llvm/llvm-project/commit/57a04e139f56b4f30b9207b50b936194c98e1b8a
DIFF: https://github.com/llvm/llvm-project/commit/57a04e139f56b4f30b9207b50b936194c98e1b8a.diff
LOG: Revert "[Clang] Support friend declarations with a dependent nested-name-spec…"
This reverts commit 0b672437c396b700fdb94bd64b176b33f084053b.
Added:
Modified:
clang-tools-extra/clang-doc/Serialize.cpp
clang/docs/ReleaseNotes.md
clang/include/clang/AST/ASTNodeTraverser.h
clang/include/clang/AST/DeclFriend.h
clang/include/clang/AST/DeclTemplate.h
clang/include/clang/AST/JSONNodeDumper.h
clang/include/clang/AST/RecursiveASTVisitor.h
clang/include/clang/AST/TextNodeDumper.h
clang/include/clang/Basic/DeclNodes.td
clang/include/clang/Basic/DiagnosticGroups.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/include/clang/Sema/Template.h
clang/include/clang/Sema/TemplateDeduction.h
clang/include/clang/Serialization/ASTBitCodes.h
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/ASTStructuralEquivalence.cpp
clang/lib/AST/DeclFriend.cpp
clang/lib/AST/DeclPrinter.cpp
clang/lib/AST/DeclTemplate.cpp
clang/lib/AST/JSONNodeDumper.cpp
clang/lib/AST/ODRHash.cpp
clang/lib/AST/TextNodeDumper.cpp
clang/lib/Index/IndexDecl.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Sema/Sema.cpp
clang/lib/Sema/SemaAccess.cpp
clang/lib/Sema/SemaCodeComplete.cpp
clang/lib/Sema/SemaConcept.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExceptionSpec.cpp
clang/lib/Sema/SemaOverload.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/lib/Sema/SemaTemplateDeductionGuide.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp
clang/test/CXX/drs/cwg18xx.cpp
clang/test/CXX/drs/cwg19xx.cpp
clang/test/CXX/drs/cwg28xx.cpp
clang/test/CXX/drs/cwg6xx.cpp
clang/test/CXX/temp/temp.decls/temp.friend/p1.cpp
clang/test/CXX/temp/temp.decls/temp.friend/p5.cpp
clang/test/Modules/odr_hash.cpp
clang/test/Parser/cxx2c-variadic-friends.cpp
clang/test/SemaCXX/cxx2c-variadic-friends.cpp
clang/test/SemaCXX/many-template-parameter-lists.cpp
clang/test/SemaTemplate/GH71595.cpp
clang/test/SemaTemplate/concepts-friends.cpp
clang/test/SemaTemplate/ctad.cpp
clang/test/SemaTemplate/friend-template.cpp
clang/test/SemaTemplate/nested-template.cpp
clang/tools/libclang/CIndex.cpp
clang/tools/libclang/CursorVisitor.h
clang/unittests/AST/DeclTest.cpp
clang/unittests/AST/StructuralEquivalenceTest.cpp
clang/www/cxx_dr_status.html
Removed:
clang/test/AST/friend-template-decl.cpp
clang/test/CXX/temp/temp.decls/temp.friend/p6.cpp
clang/test/Index/load-dependent-friend-template.cpp
clang/test/SemaTemplate/dependent-friend-constraints.cpp
################################################################################
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index 5fa23416949c4..50118e0472075 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -1029,6 +1029,9 @@ void Serializer::parseFriends(RecordInfo &RI, const CXXRecordDecl *D) {
llvm::SmallVector<FriendInfo, 4> LocalFriends;
for (const FriendDecl *FD : D->friends()) {
+ if (FD->isUnsupportedFriend())
+ continue;
+
FriendInfo F(InfoType::IT_friend, getUSRForDecl(FD));
const auto *ActualDecl = FD->getFriendDecl();
if (!ActualDecl) {
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 59ebcc4444b28..70ea2e35090c6 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -123,7 +123,6 @@ features cannot lower the translation-unit ABI level;
## What's New in Clang {{env.config.release}}?
### C++ Language Changes
-- Clang now supports friend declarations with a dependent nested name specifier. (#GH104057)
#### C++2d Feature Support
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index e00c3dd537b0d..a8a73c5b72d33 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -791,14 +791,6 @@ class ASTNodeTraverser
}
}
- void VisitFriendTemplateDecl(const FriendTemplateDecl *D) {
- for (const TemplateParameterList *TPL : D->getTemplateParameterLists())
- dumpTemplateParameters(TPL);
- if (D->getFriendKind() !=
- FriendTemplateDecl::FriendTemplateEntityKind::Template)
- VisitFriendDecl(D);
- }
-
void VisitObjCMethodDecl(const ObjCMethodDecl *D) {
if (D->isThisDeclarationADefinition())
dumpDeclContext(D);
diff --git a/clang/include/clang/AST/DeclFriend.h b/clang/include/clang/AST/DeclFriend.h
index 6d2659337a9c8..1f8c210263677 100644
--- a/clang/include/clang/AST/DeclFriend.h
+++ b/clang/include/clang/AST/DeclFriend.h
@@ -15,12 +15,18 @@
#define LLVM_CLANG_AST_DECLFRIEND_H
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/TrailingObjects.h"
#include <cassert>
#include <iterator>
@@ -43,7 +49,9 @@ class ASTContext;
/// @endcode
///
/// The semantic context of a friend decl is its declaring class.
-class FriendDecl : public Decl {
+class FriendDecl final
+ : public Decl,
+ private llvm::TrailingObjects<FriendDecl, TemplateParameterList *> {
LLVM_DECLARE_VIRTUAL_ANCHOR_FUNCTION();
public:
@@ -53,28 +61,46 @@ class FriendDecl : public Decl {
friend class CXXRecordDecl;
friend class CXXRecordDecl::friend_iterator;
- // Location of the '...', if present.
- SourceLocation EllipsisLoc;
-
- SourceLocation FriendLoc;
-
-protected:
// The declaration that's a friend of this class.
FriendUnion Friend;
+ // A pointer to the next friend in the sequence.
LazyDeclPtr NextFriend;
- FriendDecl(Kind K, DeclContext *DC, SourceLocation L, FriendUnion Friend,
- SourceLocation FL, SourceLocation EllipsisLoc = {})
- : Decl(K, DC, L), EllipsisLoc(EllipsisLoc), FriendLoc(FL), Friend(Friend),
- NextFriend() {}
+ // 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.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned UnsupportedFriend : 1;
+
+ // The number of "outer" template parameter lists in non-templatic
+ // (currently unsupported) friend type declarations, such as
+ // template <class T> friend class A<T>::B;
+ unsigned NumTPLists : 31;
+
+ FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend,
+ SourceLocation FriendL, SourceLocation EllipsisLoc,
+ ArrayRef<TemplateParameterList *> FriendTypeTPLists)
+ : Decl(Decl::Friend, DC, L), Friend(Friend), FriendLoc(FriendL),
+ EllipsisLoc(EllipsisLoc), UnsupportedFriend(false),
+ NumTPLists(FriendTypeTPLists.size()) {
+ llvm::copy(FriendTypeTPLists, getTrailingObjects());
+ }
- FriendDecl(Kind K, EmptyShell Empty) : Decl(K, Empty) {}
+ FriendDecl(EmptyShell Empty, unsigned NumFriendTypeTPLists)
+ : Decl(Decl::Friend, Empty), UnsupportedFriend(false),
+ NumTPLists(NumFriendTypeTPLists) {}
FriendDecl *getNextFriend() {
- if (NextFriend.isOffset())
- return getNextFriendSlowCase();
- return cast_or_null<FriendDecl>(NextFriend.get(nullptr));
+ if (!NextFriend.isOffset())
+ return cast_or_null<FriendDecl>(NextFriend.get(nullptr));
+ return getNextFriendSlowCase();
}
FriendDecl *getNextFriendSlowCase();
@@ -83,11 +109,14 @@ class FriendDecl : public Decl {
friend class ASTDeclReader;
friend class ASTDeclWriter;
friend class ASTNodeImporter;
+ friend TrailingObjects;
- static FriendDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- FriendUnion Friend, SourceLocation FriendL,
- SourceLocation EllipsisLoc = {});
- static FriendDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
+ static FriendDecl *
+ Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend_,
+ SourceLocation FriendL, SourceLocation EllipsisLoc = {},
+ ArrayRef<TemplateParameterList *> FriendTypeTPLists = {});
+ static FriendDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
+ unsigned FriendTypeNumTPLists);
/// If this friend declaration names an (untemplated but possibly
/// dependent) type, return the type; otherwise return null. This
@@ -97,26 +126,72 @@ class FriendDecl : public Decl {
return Friend.dyn_cast<TypeSourceInfo*>();
}
+ unsigned getFriendTypeNumTemplateParameterLists() const {
+ return NumTPLists;
+ }
+
+ TemplateParameterList *getFriendTypeTemplateParameterList(unsigned N) const {
+ return getTrailingObjects(NumTPLists)[N];
+ }
+
/// If this friend declaration doesn't name a type, return the inner
/// declaration.
- virtual NamedDecl *getFriendDecl() const {
+ NamedDecl *getFriendDecl() const {
return Friend.dyn_cast<NamedDecl *>();
}
+ /// Retrieves the location of the 'friend' keyword.
+ SourceLocation getFriendLoc() const {
+ return FriendLoc;
+ }
+
/// Retrieves the location of the '...', if present.
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
- SourceLocation getFriendLoc() const { return FriendLoc; }
+ /// 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<FunctionDecl>(ND))
+ return FD->getSourceRange();
+ if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(ND))
+ return FTD->getSourceRange();
+ if (const auto *CTD = dyn_cast<ClassTemplateDecl>(ND))
+ return CTD->getSourceRange();
+ if (const auto *DD = dyn_cast<DeclaratorDecl>(ND)) {
+ if (DD->getOuterLocStart() != DD->getInnerLocStart())
+ return DD->getSourceRange();
+ }
+ return SourceRange(getFriendLoc(), ND->getEndLoc());
+ }
+
+ return SourceRange(getFriendLoc(), getLocation());
+ }
- SourceRange getSourceRange() const override LLVM_READONLY;
+ /// Determines if this friend kind is unsupported.
+ bool isUnsupportedFriend() const {
+ return UnsupportedFriend;
+ }
+ void setUnsupportedFriend(bool Unsupported) {
+ 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 >= firstFriend && K <= lastFriend;
- }
+ static bool classofKind(Kind K) { return K == Decl::Friend; }
};
/// An iterator over the friend declarations of a class.
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index f5b26b0aab9ba..ed1a517247943 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -19,7 +19,6 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Redeclarable.h"
#include "clang/AST/TemplateBase.h"
@@ -2458,78 +2457,76 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
/// \code
/// template \<typename T> class A {
/// friend class MyVector<T>; // not a friend template
-/// template \<typename U> friend class B; // friend class template
+/// template \<typename U> friend class B; // not a friend template
/// template \<typename U> friend class Foo<T>::Nested; // friend template
/// };
/// \endcode
-class FriendTemplateDecl final
- : public FriendDecl,
- private llvm::TrailingObjects<FriendTemplateDecl,
- TemplateParameterList *> {
- void anchor() override;
+///
+/// \note This class is not currently in use. All of the above
+/// will yield a FriendDecl, not a FriendTemplateDecl.
+class FriendTemplateDecl : public Decl {
+ virtual void anchor();
+
+public:
+ using FriendUnion = llvm::PointerUnion<NamedDecl *,TypeSourceInfo *>;
private:
- unsigned NumTPLists = 0;
- TemplateName Template;
+ // The number of template parameters; always non-zero.
+ unsigned NumParams = 0;
- FriendTemplateDecl(DeclContext *DC, SourceLocation Loc, FriendUnion Friend,
- SourceLocation FriendLoc, SourceLocation EllipsisLoc,
- ArrayRef<TemplateParameterList *> FriendTPLists,
- TemplateName Template = {})
- : FriendDecl(Decl::FriendTemplate, DC, Loc, Friend, FriendLoc,
- EllipsisLoc),
- NumTPLists(FriendTPLists.size()), Template(Template) {
- assert(!FriendTPLists.empty());
- llvm::copy(FriendTPLists, getTrailingObjects());
- }
+ // The parameter list.
+ TemplateParameterList **Params = nullptr;
- FriendTemplateDecl(EmptyShell Empty, unsigned NumFriendTPLists)
- : FriendDecl(Decl::FriendTemplate, Empty), NumTPLists(NumFriendTPLists) {
- assert(NumFriendTPLists != 0);
- }
+ // The declaration that's a friend of this class.
+ FriendUnion Friend;
-public:
- friend class ASTDeclReader;
- friend class ASTDeclWriter;
- friend TrailingObjects;
+ // Location of the 'friend' specifier.
+ SourceLocation FriendLoc;
- enum class FriendTemplateEntityKind { Type, Template, Decl };
+ FriendTemplateDecl(DeclContext *DC, SourceLocation Loc,
+ TemplateParameterList **Params, unsigned NumParams,
+ FriendUnion Friend, SourceLocation FriendLoc)
+ : Decl(Decl::FriendTemplate, DC, Loc), NumParams(NumParams),
+ Params(Params), Friend(Friend), FriendLoc(FriendLoc) {}
- static FriendTemplateDecl *
- Create(ASTContext &Context, DeclContext *DC, SourceLocation Loc,
- FriendUnion Friend, SourceLocation FriendLoc,
- ArrayRef<TemplateParameterList *> FriendTPLists,
- SourceLocation EllipsisLoc = {}, TemplateName Template = {});
+ FriendTemplateDecl(EmptyShell Empty) : Decl(Decl::FriendTemplate, Empty) {}
+
+public:
+ friend class ASTDeclReader;
static FriendTemplateDecl *
Create(ASTContext &Context, DeclContext *DC, SourceLocation Loc,
- TemplateName Template, SourceLocation FriendLoc,
- ArrayRef<TemplateParameterList *> FriendTPLists,
- SourceLocation EllipsisLoc = {});
+ MutableArrayRef<TemplateParameterList *> Params, FriendUnion Friend,
+ SourceLocation FriendLoc);
- static FriendTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
- unsigned NumFriendTPLists);
+ static FriendTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
- SourceRange getSourceRange() const override LLVM_READONLY;
+ /// If this friend declaration names a templated type (or
+ /// a dependent member type of a templated type), return that
+ /// type; otherwise return null.
+ TypeSourceInfo *getFriendType() const {
+ return Friend.dyn_cast<TypeSourceInfo*>();
+ }
- TemplateName getFriendTemplateName() const { return Template; }
+ /// If this friend declaration names a templated function (or
+ /// a member function of a templated type), return that type;
+ /// otherwise return null.
+ NamedDecl *getFriendDecl() const {
+ return Friend.dyn_cast<NamedDecl*>();
+ }
- FriendTemplateEntityKind getFriendKind() const {
- if (getFriendType())
- return FriendTemplateEntityKind::Type;
- if (Template.isNull())
- return FriendTemplateEntityKind::Decl;
- return FriendTemplateEntityKind::Template;
+ /// Retrieves the location of the 'friend' keyword.
+ SourceLocation getFriendLoc() const {
+ return FriendLoc;
}
- NamedDecl *getFriendDecl() const override {
- if (NamedDecl *ND = Friend.dyn_cast<NamedDecl *>())
- return ND;
- return Template.getAsTemplateDecl();
+ TemplateParameterList *getTemplateParameterList(unsigned i) const {
+ assert(i <= NumParams);
+ return Params[i];
}
- ArrayRef<TemplateParameterList *> getTemplateParameterLists() const {
- return ArrayRef(getTrailingObjects(), NumTPLists);
+ unsigned getNumTemplateParameters() const {
+ return NumParams;
}
// Implement isa/cast/dyncast/etc.
diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h
index 679ce4e4815ae..4e8d1649bbf8b 100644
--- a/clang/include/clang/AST/JSONNodeDumper.h
+++ b/clang/include/clang/AST/JSONNodeDumper.h
@@ -268,7 +268,6 @@ class JSONNodeDumper
void VisitLinkageSpecDecl(const LinkageSpecDecl *LSD);
void VisitAccessSpecDecl(const AccessSpecDecl *ASD);
void VisitFriendDecl(const FriendDecl *FD);
- void VisitFriendTemplateDecl(const FriendTemplateDecl *FD);
void VisitExplicitInstantiationDecl(const ExplicitInstantiationDecl *D);
void VisitObjCIvarDecl(const ObjCIvarDecl *D);
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index d435cda19fa49..12204dcfb5938 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1739,15 +1739,17 @@ DEF_TRAVERSE_DECL(FriendDecl, {
})
DEF_TRAVERSE_DECL(FriendTemplateDecl, {
- const TemplateName Template = D->getFriendTemplateName();
if (D->getFriendType())
TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc()));
- else if (!Template.isNull())
- TRY_TO(TraverseTemplateName(Template));
else
TRY_TO(TraverseDecl(D->getFriendDecl()));
- for (TemplateParameterList *TPL : D->getTemplateParameterLists())
- TRY_TO(TraverseTemplateParameterListHelper(TPL));
+ for (unsigned I = 0, E = D->getNumTemplateParameters(); I < E; ++I) {
+ TemplateParameterList *TPL = D->getTemplateParameterList(I);
+ for (TemplateParameterList::iterator ITPL = TPL->begin(), ETPL = TPL->end();
+ ITPL != ETPL; ++ITPL) {
+ TRY_TO(TraverseDecl(*ITPL));
+ }
+ }
})
DEF_TRAVERSE_DECL(LinkageSpecDecl, {})
diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h
index 1eaafd49c2f06..41ddd88a8326c 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -399,7 +399,6 @@ class TextNodeDumper
void VisitLinkageSpecDecl(const LinkageSpecDecl *D);
void VisitAccessSpecDecl(const AccessSpecDecl *D);
void VisitFriendDecl(const FriendDecl *D);
- void VisitFriendTemplateDecl(const FriendTemplateDecl *D);
void VisitExplicitInstantiationDecl(const ExplicitInstantiationDecl *D);
void VisitObjCIvarDecl(const ObjCIvarDecl *D);
void VisitObjCMethodDecl(const ObjCMethodDecl *D);
diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td
index 114c6ae5282ef..8d1dc4936cc72 100644
--- a/clang/include/clang/Basic/DeclNodes.td
+++ b/clang/include/clang/Basic/DeclNodes.td
@@ -99,7 +99,7 @@ def FileScopeAsm : DeclNode<Decl>;
def TopLevelStmt : DeclNode<Decl>, DeclContext;
def AccessSpec : DeclNode<Decl>;
def Friend : DeclNode<Decl>;
-def FriendTemplate : DeclNode<Friend>;
+def FriendTemplate : DeclNode<Decl>;
def StaticAssert : DeclNode<Decl>;
def ExplicitInstantiation : DeclNode<Decl>;
def CXXExpansionStmt : DeclNode<Decl>, DeclContext;
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index a6cc17980e2c2..d44f69a815784 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1206,6 +1206,7 @@ def Attributes : DiagGroup<"attributes", [UnknownAttributes,
def UnknownSanitizers : DiagGroup<"unknown-sanitizers">;
def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args",
[CXX98CompatUnnamedTypeTemplateArgs]>;
+def UnsupportedFriend : DiagGroup<"unsupported-friend">;
def UnusedArgument : DiagGroup<"unused-argument">;
def UnusedCommandLineArgument : DiagGroup<"unused-command-line-argument">;
def IgnoredOptimizationArgument : DiagGroup<"ignored-optimization-argument">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 7c1e61120b0f2..b314c17ad27bd 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1934,6 +1934,16 @@ def err_friend_not_first_in_declaration : Error<
"'friend' must appear first in a non-function declaration">;
def err_using_decl_friend : Error<
"cannot befriend target of using declaration">;
+def warn_template_qualified_friend_unsupported
+ : Warning<
+ "dependent nested name specifier %0 for friend class declaration is "
+ "not supported; turning off access control for %1">,
+ InGroup<UnsupportedFriend>;
+def warn_template_qualified_friend_ignored
+ : Warning<"dependent nested name specifier %0 for friend template "
+ "declaration is "
+ "not supported; ignoring this friend declaration">,
+ InGroup<UnsupportedFriend>;
def ext_friend_tag_redecl_outside_namespace : ExtWarn<
"unqualified friend declaration referring to type outside of the nearest "
"enclosing namespace is a Microsoft extension; add a nested name specifier">,
@@ -1943,16 +1953,6 @@ 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_pack_indexing_in_friend : Error<
- "a pack indexing specifier cannot be used in a nested name specifier of a "
- "friend declaration">;
-def err_dependent_friend_not_member_of_template_spec : Error<
- "%0 does not name a class template">;
-def err_dependent_friend_not_member : Error<
- "friend declaration does not name a member of a class template specialization">;
-def err_dependent_friend_undeduced_params : Error<
- "%select{template parameter|template parameters}0 of friend declaration "
- "cannot be deduced from %1">;
def err_invalid_base_in_interface : Error<
"interface type cannot inherit from "
@@ -5325,16 +5325,11 @@ def note_ovl_candidate_deduced_mismatch : Note<
"adjusted type of %select{|element of }4argument}1,2%3">;
def note_ovl_candidate_non_deduced_mismatch : Note<
"candidate template ignored: could not match %
diff {$ against $|types}0,1">;
-def note_friend_template_non_deduced_mismatch : Note<
- "candidate friend template ignored: could not match "
- "%
diff {$ against $|types}0,1">;
// This note is needed because the above note would sometimes print two
//
diff erent types with the same name. Remove this note when the above note
// can handle that case properly.
def note_ovl_candidate_non_deduced_mismatch_qualified : Note<
"candidate template ignored: could not match %q0 against %q1">;
-def note_friend_template_non_deduced_mismatch_qualified : Note<
- "candidate friend template ignored: could not match %q0 against %q1">;
// Note that we don't treat templates
diff erently for this diagnostic.
def note_ovl_candidate_arity : Note<"candidate "
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 3cb0dcbbba83a..d931e70cb2342 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6402,15 +6402,7 @@ class Sema final : public SemaBase {
SourceLocation NameLoc,
SourceLocation EllipsisLoc,
const ParsedAttributesView &Attr,
- MultiTemplateParamsArg TempParamLists,
- TemplateIdAnnotation *TemplateId);
-
- bool CheckDependentFriend(SourceLocation Loc, NestedNameSpecifierLoc NNSLoc,
- ArrayRef<TemplateParameterList *> TPLs,
- bool IsInstantiation);
-
- bool DiagnosePackIndexingInFriendNNS(SourceLocation Loc,
- NestedNameSpecifierLoc NNSLoc);
+ MultiTemplateParamsArg TempParamLists);
MSPropertyDecl *HandleMSProperty(Scope *S, RecordDecl *TagD,
SourceLocation DeclStart, Declarator &D,
@@ -12743,18 +12735,6 @@ class Sema final : public SemaBase {
return false;
});
- /// Perform [temp.friend] p5 template argument deduction for a dependent
- /// friend declaration and a candidate class template specialization.
- bool DeduceTemplateArguments(FriendTemplateDecl *FTD,
- ClassTemplateDecl *PatternCTD,
- ClassTemplateDecl *CandidateCTD,
- ArrayRef<TemplateParameterList *> TPLs,
- ArrayRef<TemplateArgument> PatternArgs,
- ArrayRef<TemplateArgument> CandidateArgs,
- SourceLocation Loc,
- TemplateSpecCandidateSet *FailedTSC,
- MultiLevelTemplateArgumentList &DeducedArgs);
-
/// Perform template argument deduction from a function call
/// (C++ [temp.deduct.call]).
///
@@ -12981,8 +12961,7 @@ class Sema final : public SemaBase {
llvm::SmallBitVector &Used);
void MarkUsedTemplateParameters(ArrayRef<TemplateArgument> TemplateArgs,
- bool OnlyDeduced, unsigned Depth,
- llvm::SmallBitVector &Used);
+ unsigned Depth, llvm::SmallBitVector &Used);
void MarkUsedTemplateParameters(ArrayRef<TemplateArgumentLoc> TemplateArgs,
unsigned Depth, llvm::SmallBitVector &Used);
@@ -13837,11 +13816,6 @@ class Sema final : public SemaBase {
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc, DeclarationName Entity);
- TypeSourceInfo *
- SubstFriendType(TypeSourceInfo *TSI,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation Loc, DeclarationName Entity);
-
/// A form of SubstType intended specifically for instantiating the
/// type of a FunctionDecl. Its purpose is solely to force the
/// instantiation of default-argument expressions and to avoid
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 50e950e56c6ca..a3340d2f4a044 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -721,7 +721,7 @@ enum class TemplateSubstitutionKind : char {
// Helper functions for instantiating methods.
TypeSourceInfo *SubstFunctionType(FunctionDecl *D,
- SmallVectorImpl<ParmVarDecl *> &Params);
+ SmallVectorImpl<ParmVarDecl *> &Params);
bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
@@ -730,10 +730,6 @@ enum class TemplateSubstitutionKind : char {
TemplateParameterList *
SubstTemplateParams(TemplateParameterList *List);
- bool SubstTemplateParameterLists(
- ArrayRef<TemplateParameterList *> TPLs,
- SmallVectorImpl<TemplateParameterList *> &InstTPLs);
-
bool SubstQualifier(const DeclaratorDecl *OldDecl,
DeclaratorDecl *NewDecl);
bool SubstQualifier(const TagDecl *OldDecl,
@@ -744,8 +740,6 @@ enum class TemplateSubstitutionKind : char {
ArrayRef<TemplateArgument> Converted,
VarTemplateSpecializationDecl *PrevDecl = nullptr);
- bool InstantiateFriendPackExpansion(FriendDecl *D);
-
Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias);
Decl *InstantiateTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
ClassTemplatePartialSpecializationDecl *
diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h
index dd9fe46c9bf8a..39c909d73f565 100644
--- a/clang/include/clang/Sema/TemplateDeduction.h
+++ b/clang/include/clang/Sema/TemplateDeduction.h
@@ -311,11 +311,6 @@ struct DeductionFailureInfo {
}
};
-enum class TemplateSpecCandidateSetKind {
- Normal,
- FriendTemplate,
-};
-
/// TemplateSpecCandidate - This is a generalization of OverloadCandidate
/// which keeps track of template argument deduction failure info, when
/// handling explicit specializations (and instantiations) of templates
@@ -342,8 +337,7 @@ struct TemplateSpecCandidate {
}
/// Diagnose a template argument deduction failure.
- void NoteDeductionFailure(Sema &S, bool ForTakingAddress,
- TemplateSpecCandidateSetKind CandidateSetKind);
+ void NoteDeductionFailure(Sema &S, bool ForTakingAddress);
};
/// TemplateSpecCandidateSet - A set of generalized overload candidates,
@@ -359,16 +353,11 @@ class TemplateSpecCandidateSet {
// attribute on parameters.
bool ForTakingAddress;
- TemplateSpecCandidateSetKind CandidateSetKind;
-
void destroyCandidates();
public:
- TemplateSpecCandidateSet(SourceLocation Loc, bool ForTakingAddress = false,
- TemplateSpecCandidateSetKind CandidateSetKind =
- TemplateSpecCandidateSetKind::Normal)
- : Loc(Loc), ForTakingAddress(ForTakingAddress),
- CandidateSetKind(CandidateSetKind) {}
+ TemplateSpecCandidateSet(SourceLocation Loc, bool ForTakingAddress = false)
+ : Loc(Loc), ForTakingAddress(ForTakingAddress) {}
TemplateSpecCandidateSet(const TemplateSpecCandidateSet &) = delete;
TemplateSpecCandidateSet &
operator=(const TemplateSpecCandidateSet &) = delete;
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 974761b236411..b582cbdadc070 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -2123,14 +2123,6 @@ enum CtorInitializerType {
CTOR_INITIALIZER_INDIRECT_MEMBER
};
-/// Kinds of friend payloads owned by FriendTemplateDecl.
-enum FriendTemplateDeclKind {
- FTDK_Type = 0,
- FTDK_Decl = 1,
- FTDK_Template = 2,
- FTDK_Dependent = 3,
-};
-
/// Kinds of cleanup objects owned by ExprWithCleanups.
enum CleanupObjectKind { COK_Block, COK_CompoundLiteral };
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 725ebbd6ec987..01c5385ff5bb5 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -185,8 +185,6 @@ namespace clang {
return Importer.importInto(To, From);
}
- Expected<FriendDecl::FriendUnion> importFriendUnion(FriendDecl *D);
-
// Use this to import pointers of specific type.
template <typename ImportT>
[[nodiscard]] Error importInto(ImportT *&To, ImportT *From) {
@@ -541,7 +539,6 @@ namespace clang {
ExpectedDecl VisitFieldDecl(FieldDecl *D);
ExpectedDecl VisitIndirectFieldDecl(IndirectFieldDecl *D);
ExpectedDecl VisitFriendDecl(FriendDecl *D);
- ExpectedDecl VisitFriendTemplateDecl(FriendTemplateDecl *D);
ExpectedDecl VisitObjCIvarDecl(ObjCIvarDecl *D);
ExpectedDecl VisitVarDecl(VarDecl *D);
ExpectedDecl VisitImplicitParamDecl(ImplicitParamDecl *D);
@@ -4395,15 +4392,19 @@ struct FriendCountAndPosition {
static bool IsEquivalentFriend(ASTImporter &Importer, FriendDecl *FD1,
FriendDecl *FD2) {
- if (FD1->getKind() != FD2->getKind())
+ if ((!FD1->getFriendType()) != (!FD2->getFriendType()))
return false;
+ if (const TypeSourceInfo *TSI = FD1->getFriendType())
+ return Importer.IsStructurallyEquivalent(
+ TSI->getType(), FD2->getFriendType()->getType(), /*Complain=*/false);
+
ASTImporter::NonEquivalentDeclSet NonEquivalentDecls;
StructuralEquivalenceContext Ctx(
Importer.getToContext().getLangOpts(), FD1->getASTContext(),
FD2->getASTContext(), NonEquivalentDecls,
StructuralEquivalenceKind::Default,
- /*StrictTypeSpelling=*/false, /*Complain=*/false);
+ /* StrictTypeSpelling = */ false, /* Complain = */ false);
return Ctx.IsEquivalent(FD1, FD2);
}
@@ -4423,28 +4424,8 @@ static FriendCountAndPosition getFriendCountAndPosition(ASTImporter &Importer,
}
assert(FriendPosition && "Friend decl not found in own parent.");
- return {FriendCount, *FriendPosition};
-}
-
-Expected<FriendDecl::FriendUnion>
-ASTNodeImporter::importFriendUnion(FriendDecl *D) {
- if (NamedDecl *FriendD = D->getFriendDecl()) {
- NamedDecl *ToFriendD;
- if (Error Err = importInto(ToFriendD, FriendD))
- return std::move(Err);
- if (FriendD->getFriendObjectKind() != Decl::FOK_None &&
- !FriendD->isInIdentifierNamespace(Decl::IDNS_NonMemberOperator))
- ToFriendD->setObjectOfFriendDecl(false);
-
- return ToFriendD;
- }
-
- // The friend is a type, not a decl.
- auto TSIOrErr = import(D->getFriendType());
- if (TSIOrErr)
- return *TSIOrErr;
- return TSIOrErr.takeError();
+ return {FriendCount, *FriendPosition};
}
ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
@@ -4473,10 +4454,32 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
// Not found. Create it.
// The declarations will be put into order later by ImportDeclContext.
- auto ToFUOrErr = importFriendUnion(D);
- if (!ToFUOrErr)
- return ToFUOrErr.takeError();
- FriendDecl::FriendUnion ToFU = *ToFUOrErr;
+ FriendDecl::FriendUnion ToFU;
+ if (NamedDecl *FriendD = D->getFriendDecl()) {
+ NamedDecl *ToFriendD;
+ if (Error Err = importInto(ToFriendD, FriendD))
+ return std::move(Err);
+
+ if (FriendD->getFriendObjectKind() != Decl::FOK_None &&
+ !(FriendD->isInIdentifierNamespace(Decl::IDNS_NonMemberOperator)))
+ ToFriendD->setObjectOfFriendDecl(false);
+
+ ToFU = ToFriendD;
+ } else { // The friend is a type, not a decl.
+ if (auto TSIOrErr = import(D->getFriendType()))
+ ToFU = *TSIOrErr;
+ else
+ return TSIOrErr.takeError();
+ }
+
+ SmallVector<TemplateParameterList *, 1> ToTPLists(D->NumTPLists);
+ auto **FromTPLists = D->getTrailingObjects();
+ for (unsigned I = 0; I < D->NumTPLists; I++) {
+ if (auto ListOrErr = import(FromTPLists[I]))
+ ToTPLists[I] = *ListOrErr;
+ else
+ return ListOrErr.takeError();
+ }
auto LocationOrErr = import(D->getLocation());
if (!LocationOrErr)
@@ -4491,7 +4494,7 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
FriendDecl *FrD;
if (GetImportedOrCreateDecl(FrD, D, Importer.getToContext(), DC,
*LocationOrErr, ToFU, *FriendLocOrErr,
- *EllipsisLocOrErr))
+ *EllipsisLocOrErr, ToTPLists))
return FrD;
FrD->setAccess(D->getAccess());
@@ -4500,74 +4503,6 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
return FrD;
}
-ExpectedDecl ASTNodeImporter::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
- DeclContext *DC, *LexicalDC;
- if (Error Err = ImportDeclContext(D, DC, LexicalDC))
- return std::move(Err);
-
- const auto *RD = cast<CXXRecordDecl>(DC);
- SmallVector<FriendTemplateDecl *, 2> ImportedEquivalentFriends;
- for (FriendDecl *ImportedFriend : RD->friends()) {
- auto *ImportedFriendTemplate = dyn_cast<FriendTemplateDecl>(ImportedFriend);
- if (ImportedFriendTemplate &&
- IsEquivalentFriend(Importer, D, ImportedFriendTemplate))
- ImportedEquivalentFriends.push_back(ImportedFriendTemplate);
- }
-
- FriendCountAndPosition CountAndPosition =
- getFriendCountAndPosition(Importer, D);
- assert(ImportedEquivalentFriends.size() <= CountAndPosition.TotalCount &&
- "Class with non-matching friends is imported, ODR check wrong?");
-
- if (ImportedEquivalentFriends.size() == CountAndPosition.TotalCount)
- return Importer.MapImported(
- D, ImportedEquivalentFriends[CountAndPosition.IndexOfDecl]);
-
- FriendTemplateDecl::FriendUnion ToFU;
- if (D->getFriendKind() !=
- FriendTemplateDecl::FriendTemplateEntityKind::Template) {
- auto ToFUOrErr = importFriendUnion(D);
- if (!ToFUOrErr)
- return ToFUOrErr.takeError();
- ToFU = *ToFUOrErr;
- }
-
- TemplateName ToTemplate;
- const TemplateName FromTemplate = D->getFriendTemplateName();
- if (!FromTemplate.isNull()) {
- if (Error Err = importInto(ToTemplate, FromTemplate))
- return std::move(Err);
- }
-
- ArrayRef<TemplateParameterList *> FromTPLs = D->getTemplateParameterLists();
- SmallVector<TemplateParameterList *, 1> ToTPLs(FromTPLs.size());
- if (Error Err = ImportContainerChecked(FromTPLs, ToTPLs))
- return std::move(Err);
-
- auto LocationOrErr = import(D->getLocation());
- if (!LocationOrErr)
- return LocationOrErr.takeError();
-
- auto FriendLocOrErr = import(D->getFriendLoc());
- if (!FriendLocOrErr)
- return FriendLocOrErr.takeError();
-
- auto EllipsisLocOrErr = import(D->getEllipsisLoc());
- if (!EllipsisLocOrErr)
- return EllipsisLocOrErr.takeError();
-
- FriendTemplateDecl *FTD;
- if (GetImportedOrCreateDecl(FTD, D, Importer.getToContext(), DC,
- *LocationOrErr, ToFU, *FriendLocOrErr, ToTPLs,
- *EllipsisLocOrErr, ToTemplate))
- return FTD;
-
- FTD->setAccess(D->getAccess());
- FTD->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDeclInternal(FTD);
- return FTD;
-}
-
ExpectedDecl ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
// Import the major distinguishing characteristics of an ivar.
DeclContext *DC, *LexicalDC;
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index ebf4507e6e67d..d8bbfbe5dac72 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -2297,8 +2297,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
}
- return IsStructurallyEquivalent(Context, Params1->getRequiresClause(),
- Params2->getRequiresClause());
+ return true;
}
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
@@ -2435,12 +2434,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
FriendDecl *D1, FriendDecl *D2) {
- if (D1->isPackExpansion() != D2->isPackExpansion())
- return false;
-
if ((D1->getFriendType() && D2->getFriendDecl()) ||
- (D1->getFriendDecl() && D2->getFriendType()))
- return false;
+ (D1->getFriendDecl() && D2->getFriendType())) {
+ return false;
+ }
if (D1->getFriendType() && D2->getFriendType())
return IsStructurallyEquivalent(Context,
D1->getFriendType()->getType(),
@@ -2451,47 +2448,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
}
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- FriendTemplateDecl *FTD1,
- FriendTemplateDecl *FTD2) {
- if (FTD1->isPackExpansion() != FTD2->isPackExpansion())
- return false;
-
- ArrayRef<TemplateParameterList *> TPL1 = FTD1->getTemplateParameterLists();
- ArrayRef<TemplateParameterList *> TPL2 = FTD2->getTemplateParameterLists();
- if (!llvm::equal(
- TPL1, TPL2,
- [&Context](TemplateParameterList *LHS, TemplateParameterList *RHS) {
- return IsStructurallyEquivalent(Context, LHS, RHS);
- }))
- return false;
-
- auto FK1 = FTD1->getFriendKind();
- auto FK2 = FTD2->getFriendKind();
- if (FK1 != FK2)
- return false;
-
- switch (FK1) {
- case FriendTemplateDecl::FriendTemplateEntityKind::Type: {
- const TemplateName TN1 = FTD1->getFriendTemplateName();
- const TemplateName TN2 = FTD2->getFriendTemplateName();
- if (TN1.isNull() != TN2.isNull())
- return false;
- if (!IsStructurallyEquivalent(Context, FTD1->getFriendType()->getType(),
- FTD2->getFriendType()->getType()))
- return false;
- return TN1.isNull() || IsStructurallyEquivalent(Context, TN1, TN2);
- }
- case FriendTemplateDecl::FriendTemplateEntityKind::Template:
- return IsStructurallyEquivalent(Context, FTD1->getFriendTemplateName(),
- FTD2->getFriendTemplateName());
- case FriendTemplateDecl::FriendTemplateEntityKind::Decl:
- return IsStructurallyEquivalent(Context, static_cast<FriendDecl *>(FTD1),
- static_cast<FriendDecl *>(FTD2));
- }
- llvm_unreachable("unknown friend template kind");
-}
-
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
TypedefNameDecl *D1, TypedefNameDecl *D2) {
if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
diff --git a/clang/lib/AST/DeclFriend.cpp b/clang/lib/AST/DeclFriend.cpp
index d730b4f00fba2..6bfc2eb62b284 100644
--- a/clang/lib/AST/DeclFriend.cpp
+++ b/clang/lib/AST/DeclFriend.cpp
@@ -13,18 +13,28 @@
#include "clang/AST/DeclFriend.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/ExternalASTSource.h"
+#include "clang/Basic/LLVM.h"
#include <cassert>
+#include <cstddef>
using namespace clang;
void FriendDecl::anchor() {}
-FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- FriendUnion Friend, SourceLocation FriendL,
- SourceLocation EllipsisLoc) {
+FriendDecl *FriendDecl::getNextFriendSlowCase() {
+ return cast_or_null<FriendDecl>(
+ NextFriend.get(getASTContext().getExternalSource()));
+}
+
+FriendDecl *
+FriendDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ FriendUnion Friend, SourceLocation FriendL,
+ SourceLocation EllipsisLoc,
+ ArrayRef<TemplateParameterList *> FriendTypeTPLists) {
#ifndef NDEBUG
if (const auto *D = dyn_cast<NamedDecl *>(Friend)) {
assert(isa<FunctionDecl>(D) ||
@@ -36,22 +46,25 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
// to the original declaration when instantiating members.
assert(D->getFriendObjectKind() ||
(cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind()));
+ // These template parameters are for friend types only.
+ assert(FriendTypeTPLists.empty());
}
#endif
- auto *FD =
- new (C, DC) FriendDecl(Decl::Friend, DC, L, Friend, FriendL, EllipsisLoc);
+ std::size_t Extra =
+ FriendDecl::additionalSizeToAlloc<TemplateParameterList *>(
+ FriendTypeTPLists.size());
+ auto *FD = new (C, DC, Extra)
+ FriendDecl(DC, L, Friend, FriendL, EllipsisLoc, FriendTypeTPLists);
cast<CXXRecordDecl>(DC)->pushFriendDecl(FD);
return FD;
}
-FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
- return new (C, ID) FriendDecl(Decl::Friend, EmptyShell());
-}
-
-FriendDecl *FriendDecl::getNextFriendSlowCase() {
- return cast_or_null<FriendDecl>(
- NextFriend.get(getASTContext().getExternalSource()));
+FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID,
+ unsigned FriendTypeNumTPLists) {
+ std::size_t Extra =
+ additionalSizeToAlloc<TemplateParameterList *>(FriendTypeNumTPLists);
+ return new (C, ID, Extra) FriendDecl(EmptyShell(), FriendTypeNumTPLists);
}
FriendDecl *CXXRecordDecl::getFirstFriend() const {
@@ -59,29 +72,3 @@ FriendDecl *CXXRecordDecl::getFirstFriend() const {
Decl *First = data().FirstFriend.get(Source);
return First ? cast<FriendDecl>(First) : nullptr;
}
-
-SourceRange FriendDecl::getSourceRange() const {
- if (TypeSourceInfo *TInfo = getFriendType()) {
- SourceLocation EndL =
- isPackExpansion() ? getEllipsisLoc() : TInfo->getTypeLoc().getEndLoc();
- return SourceRange(getFriendLoc(), EndL);
- }
-
- if (isPackExpansion())
- return SourceRange(getFriendLoc(), getEllipsisLoc());
-
- if (NamedDecl *ND = getFriendDecl()) {
- if (const auto *FD = dyn_cast<FunctionDecl>(ND))
- return FD->getSourceRange();
- if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(ND))
- return FTD->getSourceRange();
- if (const auto *CTD = dyn_cast<ClassTemplateDecl>(ND))
- return CTD->getSourceRange();
- if (const auto *DD = dyn_cast<DeclaratorDecl>(ND)) {
- if (DD->getOuterLocStart() != DD->getInnerLocStart())
- return DD->getSourceRange();
- }
- return SourceRange(getFriendLoc(), ND->getEndLoc());
- }
- return SourceRange(getFriendLoc(), getLocation());
-}
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 1312ffd080342..4be3e977b815e 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -70,7 +70,6 @@ namespace {
void VisitEmptyDecl(EmptyDecl *D);
void VisitFunctionDecl(FunctionDecl *D);
void VisitFriendDecl(FriendDecl *D);
- void VisitFriendTemplateDecl(FriendTemplateDecl *D);
void VisitFieldDecl(FieldDecl *D);
void VisitVarDecl(VarDecl *D);
void VisitLabelDecl(LabelDecl *D);
@@ -890,17 +889,24 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
void DeclPrinter::VisitFriendDecl(FriendDecl *D) {
if (TypeSourceInfo *TSI = D->getFriendType()) {
+ unsigned NumTPLists = D->getFriendTypeNumTemplateParameterLists();
+ for (unsigned i = 0; i < NumTPLists; ++i)
+ printTemplateParameters(D->getFriendTypeTemplateParameterList(i));
Out << "friend ";
Out << TSI->getType().getAsString(Policy);
- } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D->getFriendDecl())) {
+ }
+ else if (FunctionDecl *FD =
+ dyn_cast<FunctionDecl>(D->getFriendDecl())) {
Out << "friend ";
VisitFunctionDecl(FD);
- } else if (FunctionTemplateDecl *FTD =
- dyn_cast<FunctionTemplateDecl>(D->getFriendDecl())) {
+ }
+ else if (FunctionTemplateDecl *FTD =
+ dyn_cast<FunctionTemplateDecl>(D->getFriendDecl())) {
Out << "friend ";
VisitFunctionTemplateDecl(FTD);
- } else if (ClassTemplateDecl *CTD =
- dyn_cast<ClassTemplateDecl>(D->getFriendDecl())) {
+ }
+ else if (ClassTemplateDecl *CTD =
+ dyn_cast<ClassTemplateDecl>(D->getFriendDecl())) {
Out << "friend ";
VisitRedeclarableTemplateDecl(CTD);
}
@@ -909,27 +915,6 @@ void DeclPrinter::VisitFriendDecl(FriendDecl *D) {
Out << "...";
}
-void DeclPrinter::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
- for (TemplateParameterList *TPL : D->getTemplateParameterLists())
- printTemplateParameters(TPL);
-
- TemplateName TN = D->getFriendTemplateName();
- if (D->getFriendType() || TN.isNull()) {
- VisitFriendDecl(D);
- } else {
- Out << "friend ";
- if (auto *CTD =
- dyn_cast_if_present<ClassTemplateDecl>(TN.getAsTemplateDecl()))
- Out << CTD->getTemplatedDecl()->getKindName() << ' ';
- TN.print(Out, Policy,
- Policy.SuppressScope ? TemplateName::Qualified::None
- : TemplateName::Qualified::AsWritten);
-
- if (D->isPackExpansion())
- Out << "...";
- }
-}
-
void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
prettyPrintPragmas(D);
// FIXME: add printing of pragma attributes if required.
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 6f7ce21227338..3ff6e3a3221fb 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -1236,52 +1236,21 @@ void FriendTemplateDecl::anchor() {}
FriendTemplateDecl *
FriendTemplateDecl::Create(ASTContext &Context, DeclContext *DC,
- SourceLocation Loc, FriendUnion Friend,
- SourceLocation FriendLoc,
- ArrayRef<TemplateParameterList *> FriendTPLists,
- SourceLocation EllipsisLoc, TemplateName Template) {
- std::size_t Extra =
- FriendTemplateDecl::additionalSizeToAlloc<TemplateParameterList *>(
- FriendTPLists.size());
- auto *FTD = new (Context, DC, Extra) FriendTemplateDecl(
- DC, Loc, Friend, FriendLoc, EllipsisLoc, FriendTPLists, Template);
- cast<CXXRecordDecl>(DC)->pushFriendDecl(FTD);
- return FTD;
-}
-
-FriendTemplateDecl *
-FriendTemplateDecl::Create(ASTContext &Context, DeclContext *DC,
- SourceLocation Loc, TemplateName Template,
- SourceLocation FriendLoc,
- ArrayRef<TemplateParameterList *> FriendTPLists,
- SourceLocation EllipsisLoc) {
- auto *Friend = Template.getAsTemplateDecl();
- assert(Friend && "friend template name must be resolved");
- std::size_t Extra =
- FriendTemplateDecl::additionalSizeToAlloc<TemplateParameterList *>(
- FriendTPLists.size());
- auto *FTD = new (Context, DC, Extra) FriendTemplateDecl(
- DC, Loc, Friend, FriendLoc, EllipsisLoc, FriendTPLists, Template);
- cast<CXXRecordDecl>(DC)->pushFriendDecl(FTD);
- return FTD;
+ SourceLocation L,
+ MutableArrayRef<TemplateParameterList *> Params,
+ FriendUnion Friend, SourceLocation FLoc) {
+ TemplateParameterList **TPL = nullptr;
+ if (!Params.empty()) {
+ TPL = new (Context) TemplateParameterList *[Params.size()];
+ llvm::copy(Params, TPL);
+ }
+ return new (Context, DC)
+ FriendTemplateDecl(DC, L, TPL, Params.size(), Friend, FLoc);
}
-FriendTemplateDecl *
-FriendTemplateDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID,
- unsigned NumFriendTPLists) {
- std::size_t Extra =
- FriendTemplateDecl::additionalSizeToAlloc<TemplateParameterList *>(
- NumFriendTPLists);
- return new (C, ID, Extra) FriendTemplateDecl(EmptyShell(), NumFriendTPLists);
-}
-
-SourceRange FriendTemplateDecl::getSourceRange() const {
- SourceLocation Begin = getTemplateParameterLists().front()->getTemplateLoc();
- SourceLocation End =
- !Template.isNull() && !getFriendType()
- ? (isPackExpansion() ? getEllipsisLoc() : getLocation())
- : FriendDecl::getSourceRange().getEnd();
- return SourceRange(Begin, End);
+FriendTemplateDecl *FriendTemplateDecl::CreateDeserialized(ASTContext &C,
+ GlobalDeclID ID) {
+ return new (C, ID) FriendTemplateDecl(EmptyShell());
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index b9c2272b97a4b..af54f15410789 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -1151,20 +1151,6 @@ void JSONNodeDumper::VisitFriendDecl(const FriendDecl *FD) {
attributeOnlyIfTrue("isPackExpansion", FD->isPackExpansion());
}
-void JSONNodeDumper::VisitFriendTemplateDecl(const FriendTemplateDecl *FD) {
- if (FD->getFriendKind() !=
- FriendTemplateDecl::FriendTemplateEntityKind::Template) {
- VisitFriendDecl(FD);
- return;
- }
-
- llvm::SmallString<128> Str;
- llvm::raw_svector_ostream OS(Str);
- FD->getFriendTemplateName().print(OS, PrintPolicy);
- JOS.attribute("templateName", Str);
- attributeOnlyIfTrue("isPackExpansion", FD->isPackExpansion());
-}
-
void JSONNodeDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
VisitNamedDecl(D);
JOS.attribute("type", createQualType(D->getType()));
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 297d6ba5b7686..46a4e256ea3e5 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -164,9 +164,7 @@ void ODRHash::AddTemplateName(TemplateName Name) {
case TemplateName::AssumedTemplate:
case TemplateName::SubstTemplateTemplateParm:
case TemplateName::SubstTemplateTemplateParmPack:
- break;
case TemplateName::UsingTemplate:
- AddDecl(Name.getAsUsingShadowDecl()->getTargetDecl());
break;
case TemplateName::DeducedTemplate:
llvm_unreachable("Unexpected DeducedTemplate");
@@ -222,11 +220,6 @@ void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {
for (auto *ND : TPL->asArray()) {
AddSubDecl(ND);
}
-
- const Expr *RequiresClause = TPL->getRequiresClause();
- AddBoolean(RequiresClause);
- if (RequiresClause)
- AddStmt(RequiresClause);
}
void ODRHash::clear() {
@@ -480,26 +473,6 @@ class ODRDeclVisitor : public ConstDeclVisitor<ODRDeclVisitor> {
Hash.AddBoolean(D->isPackExpansion());
}
- void VisitFriendTemplateDecl(const FriendTemplateDecl *D) {
- for (const TemplateParameterList *TPL : D->getTemplateParameterLists())
- Hash.AddTemplateParameterList(TPL);
-
- bool IsTemplateFriend =
- D->getFriendKind() ==
- FriendTemplateDecl::FriendTemplateEntityKind::Template;
- Hash.AddBoolean(!IsTemplateFriend);
- if (!IsTemplateFriend) {
- VisitFriendDecl(D);
- if (D->getFriendKind() ==
- FriendTemplateDecl::FriendTemplateEntityKind::Type &&
- !D->getFriendTemplateName().isNull())
- Hash.AddTemplateName(D->getFriendTemplateName());
- } else {
- Hash.AddTemplateName(D->getFriendTemplateName());
- Hash.AddBoolean(D->isPackExpansion());
- }
- }
-
void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
// Only care about default arguments as part of the definition.
const bool hasDefaultArgument =
@@ -584,7 +557,6 @@ bool ODRHash::isSubDeclToBeProcessed(const Decl *D, const DeclContext *Parent) {
case Decl::EnumConstant: // Only found in EnumDecl's.
case Decl::Field:
case Decl::Friend:
- case Decl::FriendTemplate:
case Decl::FunctionTemplate:
case Decl::StaticAssert:
case Decl::TypeAlias:
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index d07767aab2068..9bcc0280bbe40 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -3051,18 +3051,6 @@ void TextNodeDumper::VisitFriendDecl(const FriendDecl *D) {
OS << "...";
}
-void TextNodeDumper::VisitFriendTemplateDecl(const FriendTemplateDecl *D) {
- if (D->getFriendKind() !=
- FriendTemplateDecl::FriendTemplateEntityKind::Template) {
- VisitFriendDecl(D);
- return;
- }
-
- dumpBareTemplateName(D->getFriendTemplateName());
- if (D->isPackExpansion())
- OS << "...";
-}
-
void TextNodeDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
dumpName(D);
dumpType(D->getType());
diff --git a/clang/lib/Index/IndexDecl.cpp b/clang/lib/Index/IndexDecl.cpp
index 8b32a48483a67..df875e0b40079 100644
--- a/clang/lib/Index/IndexDecl.cpp
+++ b/clang/lib/Index/IndexDecl.cpp
@@ -763,15 +763,6 @@ class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
return true;
}
- bool VisitFriendTemplateDecl(const FriendTemplateDecl *D) {
- const NamedDecl *ND = cast<NamedDecl>(D->getDeclContext());
- if (!D->getFriendType() && D->getFriendTemplateName().isNull())
- ND = D->getFriendDecl();
- for (TemplateParameterList *TPL : D->getTemplateParameterLists())
- indexTemplateParameters(TPL, ND);
- return VisitFriendDecl(D);
- }
-
bool VisitImportDecl(const ImportDecl *D) {
return IndexCtx.importedModule(D);
}
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 0bdea354c2406..a3617c3db49c4 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1986,10 +1986,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
bool Owned = false;
SkipBodyInfo SkipBody;
- if (TemplateId &&
- (TUK != TagUseKind::Friend ||
- TemplateInfo.Kind != ParsedTemplateKind::Template ||
- TemplateId->isInvalid() || !TemplateId->Template.get().isDependent())) {
+ if (TemplateId) {
// Explicit specialization, class template partial specialization,
// or explicit instantiation.
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
@@ -2009,6 +2006,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr,
TemplateId->RAngleLoc, attrs);
+ // Friend template-ids are treated as references unless
+ // they have template headers, in which case they're ill-formed
+ // (FIXME: "template <class T> friend class A<T>::B<int>;").
+ // We diagnose this error in ActOnClassTemplateSpecialization.
} else if (TUK == TagUseKind::Reference ||
(TUK == TagUseKind::Friend &&
TemplateInfo.Kind == ParsedTemplateKind::NonTemplate)) {
@@ -2105,17 +2106,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SkipUntil(tok::semi, StopBeforeMatch);
}
- if (TemplateId) {
- Name = nullptr;
- NameLoc = TemplateId->TemplateNameLoc;
- }
-
TagOrTempResult = Actions.ActOnTemplatedFriendTag(
getCurScope(), DS.getFriendSpecLoc(), TagType, StartLoc, SS, Name,
NameLoc, EllipsisLoc, attrs,
MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0] : nullptr,
- TemplateParams ? TemplateParams->size() : 0),
- TemplateId);
+ TemplateParams ? TemplateParams->size() : 0));
} else {
if (TUK != TagUseKind::Declaration && TUK != TagUseKind::Definition)
ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index f1e328ccba426..0f291900d5612 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1178,9 +1178,8 @@ static bool IsRecordFullyDefined(const CXXRecordDecl *RD,
for (CXXRecordDecl::friend_iterator I = RD->friend_begin(),
E = RD->friend_end();
I != E && Complete; ++I) {
- FriendDecl *Friend = *I;
// Check if friend classes and methods are complete.
- if (TypeSourceInfo *TSI = Friend->getFriendType()) {
+ if (TypeSourceInfo *TSI = (*I)->getFriendType()) {
// Friend classes are available as the TypeSourceInfo of the FriendDecl.
if (CXXRecordDecl *FriendD = TSI->getType()->getAsCXXRecordDecl())
Complete = MethodsAndNestedClassesComplete(FriendD, MNCComplete);
@@ -1189,7 +1188,7 @@ static bool IsRecordFullyDefined(const CXXRecordDecl *RD,
} else {
// Friend functions are available through the NamedDecl of FriendDecl.
if (const FunctionDecl *FD =
- dyn_cast<FunctionDecl>(Friend->getFriendDecl()))
+ dyn_cast<FunctionDecl>((*I)->getFriendDecl()))
Complete = FD->isDefined();
else
// This is a template friend, give up.
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index cc2af8feb3794..9b4f59613d33b 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -21,8 +21,6 @@
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Template.h"
-#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/ScopeExit.h"
using namespace clang;
@@ -274,163 +272,7 @@ struct AccessTarget : public AccessedEntity {
mutable const CXXRecordDecl *InstanceContext;
const CXXRecordDecl *DeclaringClass;
};
-} // namespace
-static CanQual<FunctionProtoType> GetCanonicalFunctionProto(ASTContext &Context,
- QualType Ty) {
- return Context.getCanonicalType(Ty)->getAs<FunctionProtoType>();
-}
-
-static CanQual<FunctionProtoType>
-GetCanonicalFunctionProto(ASTContext &Context, const FunctionDecl *FD) {
- return GetCanonicalFunctionProto(Context, FD->getType());
-}
-
-static const TemplateSpecializationType *
-GetQualifierClassTemplateSpecializationType(ASTContext &Context,
- NestedNameSpecifier NNS) {
- if (!NNS || NNS.getKind() != NestedNameSpecifier::Kind::Type)
- return nullptr;
-
- QualType Ty(NNS.getAsType(), 0);
- if (const auto *ICNT = Ty->getAs<InjectedClassNameType>())
- Ty = ICNT->getDecl()->getCanonicalTemplateSpecializationType(Context);
-
- const auto *TST = Ty->getAsNonAliasTemplateSpecializationType();
- if (TST && isa_and_nonnull<ClassTemplateDecl>(
- TST->getTemplateName().getAsTemplateDecl()))
- return TST;
-
- return nullptr;
-}
-
-static FunctionTemplateDecl *TryGetFunctionTemplateDecl(FunctionDecl *FD) {
- if (auto *FTD = FD->getPrimaryTemplate())
- return FTD->getCanonicalDecl();
-
- if (auto *FTD = FD->getDescribedFunctionTemplate())
- return FTD->getCanonicalDecl();
-
- if (FunctionDecl *Pattern =
- FD->getTemplateInstantiationPattern(/*ForDefinition=*/false)) {
- if (auto *FTD = Pattern->getDescribedFunctionTemplate())
- return FTD->getCanonicalDecl();
- if (auto *FTD = Pattern->getPrimaryTemplate())
- return FTD->getCanonicalDecl();
- }
-
- return nullptr;
-}
-
-static ClassTemplateDecl *GetClassTemplatePattern(ClassTemplateDecl *CTD) {
- while (ClassTemplateDecl *Pattern = CTD->getInstantiatedFromMemberTemplate())
- CTD = Pattern;
- return CTD;
-}
-
-static ClassTemplateDecl *GetClassTemplateDecl(CXXRecordDecl *RD) {
- if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- return Spec->getSpecializedTemplate();
- return RD->getDescribedClassTemplate();
-}
-
-static TemplateParameterList *
-SubstTemplateParameterList(Sema &S, TemplateParameterList *TPL, DeclContext *DC,
- const MultiLevelTemplateArgumentList &Args) {
- TemplateParameterList *InstTPL =
- S.SubstTemplateParams(TPL, DC, Args,
- /*EvaluateConstraints=*/false);
- if (!InstTPL || !TPL->getRequiresClause())
- return InstTPL;
-
- ExprResult InstRequiresClause =
- S.SubstConstraintExprWithoutSatisfaction(TPL->getRequiresClause(), Args);
- if (!InstRequiresClause.isUsable())
- return nullptr;
-
- return TemplateParameterList::Create(
- S.Context, InstTPL->getTemplateLoc(), InstTPL->getLAngleLoc(),
- InstTPL->asArray(), InstTPL->getRAngleLoc(), InstRequiresClause.get());
-}
-
-static AccessResult
-DeduceTemplateArguments(Sema &S, FriendTemplateDecl *FTD, DeclContext *DC,
- const TemplateSpecializationType *TST,
- ArrayRef<TemplateParameterList *> TPLs,
- TemplateSpecCandidateSet *FailedTSC,
- MultiLevelTemplateArgumentList &DeducedArgs) {
- const auto *CandidateRD = dyn_cast<CXXRecordDecl>(DC);
- if (!CandidateRD)
- return AR_inaccessible;
-
- ClassTemplateDecl *CandidateCTD = CandidateRD->getDescribedClassTemplate();
- ArrayRef<TemplateArgument> CandidateArgs;
- if (CandidateCTD) {
- CandidateArgs = CandidateCTD->getInjectedTemplateArgs(S.Context);
- } else {
- const auto *CandidateSpec =
- dyn_cast<ClassTemplateSpecializationDecl>(CandidateRD);
- if (!CandidateSpec)
- return AR_inaccessible;
- CandidateCTD = CandidateSpec->getSpecializedTemplate();
- CandidateArgs = CandidateSpec->getTemplateArgs().asArray();
- }
-
- auto *PatternCTD = dyn_cast_if_present<ClassTemplateDecl>(
- TST->getTemplateName().getAsTemplateDecl());
- if (!PatternCTD || !declaresSameEntity(GetClassTemplatePattern(CandidateCTD),
- GetClassTemplatePattern(PatternCTD)))
- return AR_inaccessible;
-
- if (S.DeduceTemplateArguments(FTD, PatternCTD, CandidateCTD, TPLs,
- TST->template_arguments(), CandidateArgs,
- FTD->getLocation(), FailedTSC, DeducedArgs))
- return AR_accessible;
-
- return CandidateRD->isDependentContext() ? AR_dependent : AR_inaccessible;
-}
-
-class FriendTemplateMatchContext {
- Sema &S;
- FriendTemplateDecl *FTD;
- Sema::InstantiatingTemplate Inst;
- TemplateDeductionInfo Info;
- MultiLevelTemplateArgumentList DeducedArgs;
- Sema::SFINAETrap Trap;
- LocalInstantiationScope InstantiationScope;
- AccessResult Result = AR_inaccessible;
-
-public:
- FriendTemplateMatchContext(Sema &S, FriendTemplateDecl *FTD)
- : S(S), FTD(FTD), Inst(S, FTD->getLocation(), FTD),
- Info(FTD->getLocation()), Trap(S, Info), InstantiationScope(S) {}
-
- AccessResult deduce(DeclContext *DC, const TemplateSpecializationType *TST,
- ArrayRef<TemplateParameterList *> TPLs,
- TemplateSpecCandidateSet *FailedTSC) {
- if (Inst.isInvalid())
- return Result = AR_inaccessible;
- return Result = DeduceTemplateArguments(S, FTD, DC, TST, TPLs, FailedTSC,
- DeducedArgs);
- }
-
- AccessResult getAccessResult() const { return Result; }
- MultiLevelTemplateArgumentList &getDeducedArgs() { return DeducedArgs; }
-
- bool hasDeducedArgs() const { return Result == AR_accessible; }
- bool hasErrorOccurred() const { return Trap.hasErrorOccurred(); }
-};
-
-static bool HasSameFunctionType(Sema &S, QualType FriendType,
- QualType ContextType, SourceLocation Loc) {
- if (!S.Context.hasSameFunctionTypeIgnoringExceptionSpec(FriendType,
- ContextType))
- return false;
-
- const auto *FriendFPT = FriendType->castAs<FunctionProtoType>();
- const auto *ContextFPT = ContextType->castAs<FunctionProtoType>();
- return !S.CheckEquivalentExceptionSpec(S.PDiag(), S.PDiag(), FriendFPT, Loc,
- ContextFPT, Loc);
}
/// Checks whether one class might instantiate to the other.
@@ -442,12 +284,8 @@ static bool MightInstantiateTo(const CXXRecordDecl *From,
const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext();
const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext();
-
- if (FromDC == ToDC)
- return true;
-
- if (FromDC->isFileContext() || ToDC->isFileContext())
- return false;
+ if (FromDC == ToDC) return true;
+ if (FromDC->isFileContext() || ToDC->isFileContext()) return false;
// Be conservative.
return true;
@@ -505,7 +343,9 @@ static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
return OnFailure;
}
-static bool MightInstantiateTo(DeclContext *Context, DeclContext *Friend) {
+
+static bool MightInstantiateTo(Sema &S, DeclContext *Context,
+ DeclContext *Friend) {
if (Friend == Context)
return true;
@@ -524,7 +364,7 @@ static bool MightInstantiateTo(DeclContext *Context, DeclContext *Friend) {
// Asks whether the type in 'context' can ever instantiate to the type
// in 'friend'.
-static bool MightInstantiateTo(CanQualType Context, CanQualType Friend) {
+static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) {
if (Friend == Context)
return true;
@@ -535,66 +375,49 @@ static bool MightInstantiateTo(CanQualType Context, CanQualType Friend) {
return true;
}
-static bool MightInstantiateTo(CanQual<FunctionProtoType> Context,
- CanQual<FunctionProtoType> Friend) {
- if (Friend.getQualifiers() != Context.getQualifiers())
- return false;
-
- if (Friend->getNumParams() != Context->getNumParams())
+static bool MightInstantiateTo(Sema &S,
+ FunctionDecl *Context,
+ FunctionDecl *Friend) {
+ if (Context->getDeclName() != Friend->getDeclName())
return false;
- if (!MightInstantiateTo(Context->getReturnType(), Friend->getReturnType()))
+ if (!MightInstantiateTo(S,
+ Context->getDeclContext(),
+ Friend->getDeclContext()))
return false;
- for (unsigned I = 0, E = Friend->getNumParams(); I != E; ++I)
- if (!MightInstantiateTo(Context->getParamType(I), Friend->getParamType(I)))
- return false;
-
- return true;
-}
-
-static bool MightInstantiateTo(ASTContext &Ctx, DeclarationName Context,
- DeclarationName Friend) {
- if (Context == Friend)
- return true;
+ CanQual<FunctionProtoType> FriendTy
+ = S.Context.getCanonicalType(Friend->getType())
+ ->getAs<FunctionProtoType>();
+ CanQual<FunctionProtoType> ContextTy
+ = S.Context.getCanonicalType(Context->getType())
+ ->getAs<FunctionProtoType>();
- if (Context.getNameKind() != Friend.getNameKind())
+ // There isn't any way that I know of to add qualifiers
+ // during instantiation.
+ if (FriendTy.getQualifiers() != ContextTy.getQualifiers())
return false;
- switch (Context.getNameKind()) {
- case DeclarationName::CXXConstructorName:
- case DeclarationName::CXXDestructorName:
- case DeclarationName::CXXConversionFunctionName:
- return MightInstantiateTo(Ctx.getCanonicalType(Context.getCXXNameType()),
- Ctx.getCanonicalType(Friend.getCXXNameType()));
-
- default:
+ if (FriendTy->getNumParams() != ContextTy->getNumParams())
return false;
- }
-}
-static bool MightInstantiateTo(ASTContext &Ctx, FunctionDecl *Context,
- FunctionDecl *Friend) {
- if (!MightInstantiateTo(Ctx, Context->getDeclName(), Friend->getDeclName()))
+ if (!MightInstantiateTo(S, ContextTy->getReturnType(),
+ FriendTy->getReturnType()))
return false;
- DeclContext *ContextDC = Context->getDeclContext();
- DeclContext *FriendDC = Friend->getDeclContext();
-
- if (!FriendDC->isDependentContext() &&
- !MightInstantiateTo(ContextDC, FriendDC))
- return false;
-
- CanQual<FunctionProtoType> FriendTy = GetCanonicalFunctionProto(Ctx, Friend);
- CanQual<FunctionProtoType> ContextTy =
- GetCanonicalFunctionProto(Ctx, Context);
+ for (unsigned I = 0, E = FriendTy->getNumParams(); I != E; ++I)
+ if (!MightInstantiateTo(S, ContextTy->getParamType(I),
+ FriendTy->getParamType(I)))
+ return false;
- return MightInstantiateTo(ContextTy, FriendTy);
+ return true;
}
-static bool MightInstantiateTo(ASTContext &Ctx, FunctionTemplateDecl *Context,
+static bool MightInstantiateTo(Sema &S,
+ FunctionTemplateDecl *Context,
FunctionTemplateDecl *Friend) {
- return MightInstantiateTo(Ctx, Context->getTemplatedDecl(),
+ return MightInstantiateTo(S,
+ Context->getTemplatedDecl(),
Friend->getTemplatedDecl());
}
@@ -655,7 +478,7 @@ static AccessResult MatchesFriend(Sema &S,
}
// It's a match.
- if (declaresSameEntity(Friend, CTD))
+ if (Friend == CTD->getCanonicalDecl())
return AR_accessible;
// If the context isn't dependent, it can't be a dependent match.
@@ -669,7 +492,8 @@ static AccessResult MatchesFriend(Sema &S,
// If the class's context can't instantiate to the friend's
// context, it can't be a dependent match.
- if (!MightInstantiateTo(CTD->getDeclContext(), Friend->getDeclContext()))
+ if (!MightInstantiateTo(S, CTD->getDeclContext(),
+ Friend->getDeclContext()))
continue;
// Otherwise, it's a dependent match.
@@ -691,7 +515,7 @@ static AccessResult MatchesFriend(Sema &S,
if (Friend == *I)
return AR_accessible;
- if (EC.isDependent() && MightInstantiateTo(S.Context, *I, Friend))
+ if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))
OnFailure = AR_dependent;
}
@@ -710,390 +534,21 @@ static AccessResult MatchesFriend(Sema &S,
for (SmallVectorImpl<FunctionDecl*>::const_iterator
I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
- FunctionTemplateDecl *FTD = TryGetFunctionTemplateDecl(*I);
+ FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate();
+ if (!FTD)
+ FTD = (*I)->getDescribedFunctionTemplate();
if (!FTD)
continue;
- if (Friend == FTD)
- return AR_accessible;
-
- if (EC.isDependent() && MightInstantiateTo(S.Context, FTD, Friend))
- OnFailure = AR_dependent;
- }
-
- return OnFailure;
-}
-
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- NamedDecl *ND) {
- ND = cast<NamedDecl>(ND->getCanonicalDecl());
- if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(ND))
- return MatchesFriend(S, EC, CTD);
-
- if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
- return MatchesFriend(S, EC, FTD);
-
- if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND))
- return MatchesFriend(S, EC, RD);
-
- assert(isa<FunctionDecl>(ND) && "unknown friend decl kind");
- return MatchesFriend(S, EC, cast<FunctionDecl>(ND));
-}
-
-static AccessResult MatchesFriend(Sema &S, FriendTemplateDecl *FTD,
- DeclarationName FriendName,
- TagTypeKind FriendTagKind,
- ClassTemplateDecl *ContextCTD,
- const TemplateSpecializationType *FriendTST,
- ArrayRef<TemplateParameterList *> TPLs,
- TemplateParameterList *MemberTPL,
- TemplateSpecCandidateSet *FailedTSC) {
- if (FriendName != ContextCTD->getDeclName())
- return AR_inaccessible;
-
- if ((FriendTagKind == TagTypeKind::Union) !=
- ContextCTD->getTemplatedDecl()->isUnion())
- return AR_inaccessible;
-
- DeclContext *ContextDC = ContextCTD->getDeclContext();
- AccessResult OnFailure =
- ContextDC->isDependentContext() ? AR_dependent : AR_inaccessible;
-
- FriendTemplateMatchContext FTMC(S, FTD);
- AccessResult Result = FTMC.deduce(ContextDC, FriendTST, TPLs, FailedTSC);
- if (!FTMC.hasDeducedArgs())
- return Result;
-
- TemplateParameterList *InstTPL = SubstTemplateParameterList(
- S, MemberTPL, ContextDC, FTMC.getDeducedArgs());
- if (!InstTPL || FTMC.hasErrorOccurred())
- return OnFailure;
-
- Sema::TemplateCompareNewDeclInfo FriendInfo(
- ContextDC, FTD->getLexicalDeclContext(), FTD->getLocation());
- if (S.TemplateParameterListsAreEqual(
- FriendInfo, InstTPL, ContextCTD, ContextCTD->getTemplateParameters(),
- /*Complain=*/false, Sema::TPL_TemplateMatch))
- return AR_accessible;
- return OnFailure;
-}
-
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- FriendTemplateDecl *FTD,
- ClassTemplateDecl *FriendCTD,
- NestedNameSpecifier Qualifier,
- TemplateSpecCandidateSet *FailedTSC) {
- const auto *FriendTST =
- GetQualifierClassTemplateSpecializationType(S.Context, Qualifier);
- if (!FriendTST)
- return MatchesFriend(S, EC, FriendCTD);
-
- ArrayRef<TemplateParameterList *> TPLs = FTD->getTemplateParameterLists();
-
- AccessResult OnFailure = AR_inaccessible;
- for (CXXRecordDecl *ContextRD : EC.Records) {
- ClassTemplateDecl *ContextCTD = GetClassTemplateDecl(ContextRD);
- if (!ContextCTD)
- continue;
-
- AccessResult Result =
- MatchesFriend(S, FTD, FriendCTD->getDeclName(),
- FriendCTD->getTemplatedDecl()->getTagKind(), ContextCTD,
- FriendTST, TPLs.drop_back(), TPLs.back(), FailedTSC);
- if (Result == AR_accessible)
- return AR_accessible;
- if (Result == AR_dependent)
- OnFailure = AR_dependent;
- }
-
- return OnFailure;
-}
-
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- FriendTemplateDecl *FTD,
- TemplateName FriendTemplate,
- ClassTemplateDecl *FriendCTD,
- TemplateSpecCandidateSet *FailedTSC) {
- NestedNameSpecifier Qualifier = FriendTemplate.getQualifier();
- if (FriendTemplate.getAsUsingShadowDecl())
- Qualifier = FriendCTD->getTemplatedDecl()->getQualifier();
- return MatchesFriend(S, EC, FTD, FriendCTD, Qualifier, FailedTSC);
-}
-
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- FriendTemplateDecl *FTD,
- ClassTemplateDecl *FriendCTD,
- TemplateSpecCandidateSet *FailedTSC) {
- return MatchesFriend(S, EC, FTD, FriendCTD,
- FriendCTD->getTemplatedDecl()->getQualifier(),
- FailedTSC);
-}
-
-static AccessResult MatchesFriend(Sema &S, FriendTemplateDecl *FTD,
- FunctionDecl *FriendFD,
- FunctionDecl *ContextFD,
- const TemplateSpecializationType *FriendTST,
- ArrayRef<TemplateParameterList *> TPLs,
- TemplateSpecCandidateSet *FailedTSC) {
- if (!MightInstantiateTo(S.Context, ContextFD->getDeclName(),
- FriendFD->getDeclName()))
- return AR_inaccessible;
-
- FunctionTemplateDecl *FriendTemplate =
- FriendFD->getDescribedFunctionTemplate();
- FunctionTemplateDecl *ContextTemplate = TryGetFunctionTemplateDecl(ContextFD);
-
- if (FriendTemplate && !ContextTemplate)
- return AR_inaccessible;
-
- DeclContext *ContextDC = ContextFD->getDeclContext();
- AccessResult OnFailure =
- ContextDC->isDependentContext() ? AR_dependent : AR_inaccessible;
-
- FriendTemplateMatchContext FTMC(S, FTD);
- AccessResult Result = FTMC.deduce(ContextDC, FriendTST, TPLs, FailedTSC);
- if (!FTMC.hasDeducedArgs())
- return Result;
-
- Sema::TemplateCompareNewDeclInfo FriendInfo(
- ContextDC, FTD->getLexicalDeclContext(), FTD->getLocation());
- if (FriendTemplate) {
- TemplateParameterList *InstTPL =
- SubstTemplateParameterList(S, FriendTemplate->getTemplateParameters(),
- ContextDC, FTMC.getDeducedArgs());
- if (!InstTPL || !S.TemplateParameterListsAreEqual(
- FriendInfo, InstTPL, ContextTemplate,
- ContextTemplate->getTemplateParameters(),
- /*Complain=*/false, Sema::TPL_TemplateMatch))
- return OnFailure;
-
- ContextFD = ContextTemplate->getTemplatedDecl();
- }
-
- Sema::ContextRAII SavedContext(S, FTD->getDeclContext());
- QualType InstFriendType =
- S.SubstType(FriendFD->getType(), FTMC.getDeducedArgs(),
- FriendFD->getLocation(), FriendFD->getDeclName());
- SavedContext.pop();
- if (InstFriendType.isNull() || FTMC.hasErrorOccurred())
- return OnFailure;
-
- if (ContextTemplate && !FriendTemplate) {
- AccessResult OnSpecializationFailure =
- ContextFD->isDependentContext() ? AR_dependent : OnFailure;
- const ASTTemplateArgumentListInfo *ArgsWritten =
- FriendFD->getTemplateSpecializationArgsAsWritten();
- TemplateArgumentListInfo InstArgs;
- if (ArgsWritten) {
- InstArgs.setLAngleLoc(ArgsWritten->getLAngleLoc());
- InstArgs.setRAngleLoc(ArgsWritten->getRAngleLoc());
- if (S.SubstTemplateArguments(ArgsWritten->arguments(),
- FTMC.getDeducedArgs(), InstArgs))
- return OnSpecializationFailure;
- }
-
- FunctionDecl *ContextSpecialization = nullptr;
- TemplateDeductionInfo FunctionInfo(FTD->getLocation());
- if (S.DeduceTemplateArguments(
- ContextTemplate, ArgsWritten ? &InstArgs : nullptr, InstFriendType,
- ContextSpecialization,
- FunctionInfo) != TemplateDeductionResult::Success ||
- !ContextSpecialization || FTMC.hasErrorOccurred() ||
- !declaresSameEntity(ContextSpecialization, ContextFD))
- return OnSpecializationFailure;
-
- ContextFD = ContextSpecialization;
- }
-
- if (!HasSameFunctionType(S, InstFriendType, ContextFD->getType(),
- FTD->getLocation()) ||
- FTMC.hasErrorOccurred())
- return OnFailure;
-
- if (!FriendTemplate)
- return AR_accessible;
-
- AssociatedConstraint FriendRequiresClause =
- FriendFD->getTrailingRequiresClause();
- AssociatedConstraint ContextRequiresClause =
- ContextFD->getTrailingRequiresClause();
- if (FriendRequiresClause.isNull() != ContextRequiresClause.isNull())
- return AR_inaccessible;
-
- if (!FriendRequiresClause)
- return AR_accessible;
-
- ExprResult InstFriendRequiresClause =
- S.SubstConstraintExprWithoutSatisfaction(
- const_cast<Expr *>(FriendRequiresClause.ConstraintExpr),
- FTMC.getDeducedArgs());
+ FTD = FTD->getCanonicalDecl();
- if (!InstFriendRequiresClause.isUsable())
- return OnFailure;
-
- if (!S.AreConstraintExpressionsEqual(
- ContextFD, ContextRequiresClause.ConstraintExpr, FriendInfo,
- InstFriendRequiresClause.get()))
- return OnFailure;
- return FTMC.hasErrorOccurred() ? AR_inaccessible : AR_accessible;
-}
-
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- FriendTemplateDecl *FTD,
- FunctionDecl *FriendFD,
- TemplateSpecCandidateSet *FailedTSC) {
- const auto *FriendTST = GetQualifierClassTemplateSpecializationType(
- S.Context, FriendFD->getQualifier());
- if (!FriendTST)
- return AR_inaccessible;
-
- ArrayRef<TemplateParameterList *> TPLs = FTD->getTemplateParameterLists();
-
- AccessResult OnFailure = AR_inaccessible;
- for (FunctionDecl *ContextFD : EC.Functions) {
- AccessResult Result =
- MatchesFriend(S, FTD, FriendFD, ContextFD, FriendTST, TPLs, FailedTSC);
- if (Result == AR_accessible)
+ if (Friend == FTD)
return AR_accessible;
- if (Result == AR_dependent)
+ if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
OnFailure = AR_dependent;
}
- return OnFailure;
-}
-
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- FriendTemplateDecl *FTD, NamedDecl *Friend,
- TemplateSpecCandidateSet *FailedTSC) {
- TemplateName FriendTemplate = FTD->getFriendTemplateName();
- if (auto *FriendCTD = dyn_cast_if_present<ClassTemplateDecl>(
- FriendTemplate.getAsTemplateDecl()))
- return MatchesFriend(S, EC, FTD, FriendTemplate, FriendCTD, FailedTSC);
- if (auto *FriendCTD = dyn_cast<ClassTemplateDecl>(Friend))
- return MatchesFriend(S, EC, FTD, FriendCTD, FailedTSC);
- if (FunctionDecl *FriendFD = Friend->getAsFunction())
- return MatchesFriend(S, EC, FTD, FriendFD, FailedTSC);
- return MatchesFriend(S, EC, Friend);
-}
-
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- FriendTemplateDecl *FTD,
- TypeSourceInfo *FriendTSI,
- TemplateSpecCandidateSet *FailedTSC) {
- QualType FriendType = FriendTSI->getType();
- if (!FriendType->isDependentType())
- return MatchesFriend(S, EC, S.Context.getCanonicalType(FriendType));
-
- AccessResult OnFailure = AR_inaccessible;
- if (auto FriendTSTL =
- FriendTSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>()) {
- const auto *FriendTST = FriendTSTL.getTypePtr();
- const auto *FriendQTST = GetQualifierClassTemplateSpecializationType(
- S.Context, FriendTSTL.getQualifierLoc().getNestedNameSpecifier());
- if (!FriendQTST)
- return OnFailure;
-
- ArrayRef<TemplateParameterList *> TPLs = FTD->getTemplateParameterLists();
-
- TemplateName FriendTemplate = FriendTST->getTemplateName();
- DeclarationName FriendName;
- if (TemplateDecl *TD = FriendTemplate.getAsTemplateDecl())
- FriendName = TD->getDeclName();
- else if (DependentTemplateName *DTN =
- FriendTemplate.getAsDependentTemplateName())
- FriendName = DTN->getName().getIdentifier();
-
- TagTypeKind FriendTagKind =
- TypeWithKeyword::getTagTypeKindForKeyword(FriendTST->getKeyword());
-
- for (CXXRecordDecl *ContextRD : EC.Records) {
- ClassTemplateDecl *ContextCTD = GetClassTemplateDecl(ContextRD);
- if (!ContextCTD)
- continue;
-
- if (FriendName && ContextCTD->getDeclName() != FriendName)
- continue;
-
- if ((FriendTagKind == TagTypeKind::Union) !=
- ContextCTD->getTemplatedDecl()->isUnion())
- continue;
-
- FriendTemplateMatchContext FTMC(S, FTD);
- AccessResult Result =
- FTMC.deduce(ContextRD->getDeclContext(), FriendQTST, TPLs, FailedTSC);
- if (!FTMC.hasDeducedArgs()) {
- if (Result == AR_dependent)
- OnFailure = AR_dependent;
- continue;
- }
-
- TypeSourceInfo *InstFriendTSI =
- S.SubstFriendType(FriendTSI, FTMC.getDeducedArgs(),
- FTD->getLocation(), DeclarationName());
- if (InstFriendTSI && !FTMC.hasErrorOccurred() &&
- S.Context.hasSameType(InstFriendTSI->getType(),
- S.Context.getCanonicalTagType(ContextRD)))
- return AR_accessible;
-
- if (ContextRD->isDependentContext())
- OnFailure = AR_dependent;
- }
-
- return OnFailure;
- }
-
- const auto *FriendDNT = FriendType->getAs<DependentNameType>();
- if (!FriendDNT)
- return OnFailure;
-
- const auto *FriendTST = GetQualifierClassTemplateSpecializationType(
- S.Context, FriendDNT->getQualifier());
- if (!FriendTST)
- return OnFailure;
- ArrayRef<TemplateParameterList *> TPLs = FTD->getTemplateParameterLists();
-
- TagTypeKind FriendTagKind =
- TypeWithKeyword::getTagTypeKindForKeyword(FriendDNT->getKeyword());
- for (CXXRecordDecl *ContextRD : EC.Records) {
- if (ContextRD->getDeclName() != FriendDNT->getIdentifier())
- continue;
-
- if (ClassTemplateDecl *ContextCTD = GetClassTemplateDecl(ContextRD)) {
- if (FTD->getFriendTemplateName().isNull()) {
- if (FailedTSC) {
- MultiLevelTemplateArgumentList DeducedArgs;
- DeduceTemplateArguments(S, FTD, ContextCTD->getDeclContext(),
- FriendTST, TPLs, FailedTSC, DeducedArgs);
- }
- continue;
- }
-
- AccessResult Result = MatchesFriend(
- S, FTD, FriendDNT->getIdentifier(), FriendTagKind, ContextCTD,
- FriendTST, TPLs.drop_back(), TPLs.back(), FailedTSC);
- if (Result == AR_accessible)
- return AR_accessible;
- if (Result == AR_dependent)
- OnFailure = AR_dependent;
- continue;
- }
-
- if (!FTD->getFriendTemplateName().isNull())
- continue;
-
- if ((FriendTagKind == TagTypeKind::Union) != ContextRD->isUnion())
- continue;
-
- MultiLevelTemplateArgumentList DeducedArgs;
- AccessResult Result =
- DeduceTemplateArguments(S, FTD, ContextRD->getDeclContext(), FriendTST,
- TPLs, FailedTSC, DeducedArgs);
- if (Result == AR_accessible)
- return AR_accessible;
- if (Result == AR_dependent)
- OnFailure = AR_dependent;
- }
return OnFailure;
}
@@ -1102,47 +557,40 @@ static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
static AccessResult MatchesFriend(Sema &S,
const EffectiveContext &EC,
FriendDecl *FriendD) {
- // Whitelist accesses if there's an invalid friend declaration.
- if (FriendD->isInvalidDecl())
+ // Whitelist accesses if there's an invalid or unsupported friend
+ // declaration.
+ if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend())
return AR_accessible;
- if (NamedDecl *Friend = FriendD->getFriendDecl())
- return MatchesFriend(S, EC, Friend);
-
if (TypeSourceInfo *T = FriendD->getFriendType())
return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
- return AR_inaccessible;
-}
+ NamedDecl *Friend
+ = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl());
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- FriendTemplateDecl *FTD,
- TemplateSpecCandidateSet *FailedTSC) {
- if (FTD->isInvalidDecl())
- return AR_accessible;
+ // FIXME: declarations with dependent or templated scope.
+
+ if (isa<ClassTemplateDecl>(Friend))
+ return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend));
+
+ if (isa<FunctionTemplateDecl>(Friend))
+ return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend));
- if (TypeSourceInfo *TSI = FTD->getFriendType())
- return MatchesFriend(S, EC, FTD, TSI, FailedTSC);
+ if (isa<CXXRecordDecl>(Friend))
+ return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend));
- NamedDecl *Friend = FTD->getFriendDecl();
- assert(Friend && "friend template must name a type or declaration");
- return MatchesFriend(S, EC, FTD, Friend, FailedTSC);
+ assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind");
+ return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
}
-static AccessResult GetFriendKind(Sema &S, const EffectiveContext &EC,
- const CXXRecordDecl *Class,
- TemplateSpecCandidateSet *FailedTSC) {
+static AccessResult GetFriendKind(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *Class) {
AccessResult OnFailure = AR_inaccessible;
// Okay, check friends.
- for (FriendDecl *Friend : Class->friends()) {
- AccessResult AR;
- if (auto *FTD = dyn_cast<FriendTemplateDecl>(Friend))
- AR = MatchesFriend(S, EC, FTD, FailedTSC);
- else
- AR = MatchesFriend(S, EC, Friend);
-
- switch (AR) {
+ for (auto *Friend : Class->friends()) {
+ switch (MatchesFriend(S, EC, Friend)) {
case AR_accessible:
return AR_accessible;
@@ -1166,7 +614,6 @@ namespace {
struct ProtectedFriendContext {
Sema &S;
const EffectiveContext &EC;
- TemplateSpecCandidateSet *FailedTSC;
const CXXRecordDecl *NamingClass;
bool CheckDependent;
bool EverDependent;
@@ -1176,19 +623,18 @@ struct ProtectedFriendContext {
ProtectedFriendContext(Sema &S, const EffectiveContext &EC,
const CXXRecordDecl *InstanceContext,
- const CXXRecordDecl *NamingClass,
- TemplateSpecCandidateSet *FailedTSC)
- : S(S), EC(EC), FailedTSC(FailedTSC), NamingClass(NamingClass),
- CheckDependent(InstanceContext->isDependentContext() ||
- NamingClass->isDependentContext()),
- EverDependent(false) {}
+ const CXXRecordDecl *NamingClass)
+ : S(S), EC(EC), NamingClass(NamingClass),
+ CheckDependent(InstanceContext->isDependentContext() ||
+ NamingClass->isDependentContext()),
+ EverDependent(false) {}
/// Check classes in the current path for friendship, starting at
/// the given index.
bool checkFriendshipAlongPath(unsigned I) {
assert(I < CurPath.size());
for (unsigned E = CurPath.size(); I != E; ++I) {
- switch (GetFriendKind(S, EC, CurPath[I], FailedTSC)) {
+ switch (GetFriendKind(S, EC, CurPath[I])) {
case AR_accessible: return true;
case AR_inaccessible: continue;
case AR_dependent: EverDependent = true; continue;
@@ -1275,9 +721,9 @@ struct ProtectedFriendContext {
/// because the original target might have been more accessible
/// because of crazy subclassing.
/// So we don't implement that.
-static AccessResult GetProtectedFriendKind(
- Sema &S, const EffectiveContext &EC, const CXXRecordDecl *InstanceContext,
- const CXXRecordDecl *NamingClass, TemplateSpecCandidateSet *FailedTSC) {
+static AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC,
+ const CXXRecordDecl *InstanceContext,
+ const CXXRecordDecl *NamingClass) {
assert(InstanceContext == nullptr ||
InstanceContext->getCanonicalDecl() == InstanceContext);
assert(NamingClass->getCanonicalDecl() == NamingClass);
@@ -1285,20 +731,19 @@ static AccessResult GetProtectedFriendKind(
// If we don't have an instance context, our constraints give us
// that NamingClass <= P <= NamingClass, i.e. P == NamingClass.
// This is just the usual friendship check.
- if (!InstanceContext)
- return GetFriendKind(S, EC, NamingClass, FailedTSC);
+ if (!InstanceContext) return GetFriendKind(S, EC, NamingClass);
- ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass, FailedTSC);
+ ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass);
if (PRC.findFriendship(InstanceContext)) return AR_accessible;
if (PRC.EverDependent) return AR_dependent;
return AR_inaccessible;
}
-static AccessResult HasAccess(Sema &S, const EffectiveContext &EC,
+static AccessResult HasAccess(Sema &S,
+ const EffectiveContext &EC,
const CXXRecordDecl *NamingClass,
AccessSpecifier Access,
- const AccessTarget &Target,
- TemplateSpecCandidateSet *FailedTSC) {
+ const AccessTarget &Target) {
assert(NamingClass->getCanonicalDecl() == NamingClass &&
"declaration should be canonicalized before being passed here");
@@ -1418,8 +863,7 @@ static AccessResult HasAccess(Sema &S, const EffectiveContext &EC,
if (!InstanceContext) return AR_dependent;
}
- switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass,
- FailedTSC)) {
+ switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass)) {
case AR_accessible: return AR_accessible;
case AR_inaccessible: return OnFailure;
case AR_dependent: return AR_dependent;
@@ -1427,7 +871,7 @@ static AccessResult HasAccess(Sema &S, const EffectiveContext &EC,
llvm_unreachable("impossible friendship kind");
}
- switch (GetFriendKind(S, EC, NamingClass, FailedTSC)) {
+ switch (GetFriendKind(S, EC, NamingClass)) {
case AR_accessible: return AR_accessible;
case AR_inaccessible: return OnFailure;
case AR_dependent: return AR_dependent;
@@ -1540,8 +984,7 @@ static CXXBasePath *FindBestPath(Sema &S,
AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
PathAccess = std::max(PathAccess, BaseAccess);
- switch (HasAccess(S, EC, NC, PathAccess, Target,
- /*FailedTSC=*/nullptr)) {
+ switch (HasAccess(S, EC, NC, PathAccess, Target)) {
case AR_inaccessible: break;
case AR_accessible:
PathAccess = AS_public;
@@ -1737,8 +1180,7 @@ static void DiagnoseAccessPath(Sema &S,
accessSoFar = D->getAccess();
const CXXRecordDecl *declaringClass = entity.getDeclaringClass();
- switch (HasAccess(S, EC, declaringClass, accessSoFar, entity,
- /*FailedTSC=*/nullptr)) {
+ switch (HasAccess(S, EC, declaringClass, accessSoFar, entity)) {
// If the declaration is accessible when named in its declaring
// class, then we must be constrained by the path.
case AR_accessible:
@@ -1781,8 +1223,7 @@ static void DiagnoseAccessPath(Sema &S,
accessSoFar = baseAccess;
}
- switch (HasAccess(S, EC, derivingClass, accessSoFar, entity,
- /*FailedTSC=*/nullptr)) {
+ switch (HasAccess(S, EC, derivingClass, accessSoFar, entity)) {
case AR_inaccessible: break;
case AR_accessible:
accessSoFar = AS_public;
@@ -1886,9 +1327,9 @@ static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,
/// Determines whether the accessed entity is accessible. Public members
/// have been weeded out by this point.
-static AccessResult IsAccessible(Sema &S, const EffectiveContext &EC,
- AccessTarget &Entity,
- TemplateSpecCandidateSet *FailedTSC) {
+static AccessResult IsAccessible(Sema &S,
+ const EffectiveContext &EC,
+ AccessTarget &Entity) {
// Determine the actual naming class.
const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass();
@@ -1900,8 +1341,7 @@ static AccessResult IsAccessible(Sema &S, const EffectiveContext &EC,
// which don't require [M4] or [B4]. These are by far the most
// common forms of privileged access.
if (UnprivilegedAccess != AS_none) {
- switch (
- HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity, FailedTSC)) {
+ switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) {
case AR_dependent:
// This is actually an interesting policy decision. We don't
// *have* to delay immediately here: we can do the full access
@@ -1930,7 +1370,7 @@ static AccessResult IsAccessible(Sema &S, const EffectiveContext &EC,
const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
FinalAccess = Target->getAccess();
- switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity, FailedTSC)) {
+ switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) {
case AR_accessible:
// Target is accessible at EC when named in its declaring class.
// We can now hill-climb and simply check whether the declaring
@@ -1982,30 +1422,25 @@ static void DelayDependentAccess(Sema &S,
Entity.getDiag());
}
-static AccessResult CheckEffectiveAccess(Sema &S, const EffectiveContext &EC,
+/// Checks access to an entity from the given effective context.
+static AccessResult CheckEffectiveAccess(Sema &S,
+ const EffectiveContext &EC,
SourceLocation Loc,
- AccessTarget &Entity,
- TemplateSpecCandidateSet *FailedTSC) {
- assert((Entity.isQuiet() || FailedTSC) &&
- "non-quiet access check requires a candidate set");
+ AccessTarget &Entity) {
+ assert(Entity.getAccess() != AS_public && "called for public access!");
- switch (IsAccessible(S, EC, Entity, FailedTSC)) {
+ switch (IsAccessible(S, EC, Entity)) {
case AR_dependent:
DelayDependentAccess(S, EC, Loc, Entity);
return AR_dependent;
- case AR_inaccessible: {
+ case AR_inaccessible:
if (S.getLangOpts().MSVCCompat &&
IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity))
return AR_accessible;
-
- if (Entity.isQuiet())
- return AR_inaccessible;
-
- DiagnoseBadAccess(S, Loc, EC, Entity);
- FailedTSC->NoteCandidates(S, Loc);
+ if (!Entity.isQuiet())
+ DiagnoseBadAccess(S, Loc, EC, Entity);
return AR_inaccessible;
- }
case AR_accessible:
return AR_accessible;
@@ -2015,20 +1450,6 @@ static AccessResult CheckEffectiveAccess(Sema &S, const EffectiveContext &EC,
llvm_unreachable("invalid access result");
}
-static AccessResult CheckEffectiveAccess(Sema &S, const EffectiveContext &EC,
- SourceLocation Loc,
- AccessTarget &Entity) {
- assert(Entity.getAccess() != AS_public && "called for public access!");
-
- if (Entity.isQuiet())
- return CheckEffectiveAccess(S, EC, Loc, Entity, /*FailedTSC=*/nullptr);
-
- TemplateSpecCandidateSet FailedTSC(
- Loc, /*ForTakingAddress=*/false,
- TemplateSpecCandidateSetKind::FriendTemplate);
- return CheckEffectiveAccess(S, EC, Loc, Entity, &FailedTSC);
-}
-
static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
AccessTarget &Entity) {
// If the access path is public, it's accessible everywhere.
@@ -2523,8 +1944,7 @@ bool Sema::IsSimplyAccessible(NamedDecl *Target, CXXRecordDecl *NamingClass,
AccessTarget Entity(Context, AccessedEntity::Member, NamingClass,
DeclAccessPair::make(Target, AS_none), BaseType);
EffectiveContext EC(CurContext);
- return ::IsAccessible(*this, EC, Entity, /*FailedTSC=*/nullptr) !=
- ::AR_inaccessible;
+ return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible;
}
if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Target)) {
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 3b3c9a476421d..bd239adb0f215 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -4497,7 +4497,6 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) {
case Decl::StaticAssert:
return CXCursor_StaticAssert;
case Decl::Friend:
- case Decl::FriendTemplate:
return CXCursor_FriendDecl;
case Decl::TranslationUnit:
return CXCursor_TranslationUnit;
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 606cfe7bdcf73..ce91099cd037c 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -2175,10 +2175,9 @@ void SubstituteParameterMappings::buildParameterMapping(
assert(Arg && "expected a default argument");
DefaultArgs.emplace_back(std::move(*Arg));
}
- SemaRef.MarkUsedTemplateParameters(DefaultArgs, /*OnlyDeduced=*/false,
- /*Depth=*/0, OccurringIndices);
- SemaRef.MarkUsedTemplateParameters(DefaultArgs, /*OnlyDeduced=*/false,
- /*Depth=*/0,
+ SemaRef.MarkUsedTemplateParameters(DefaultArgs, /*Depth=*/0,
+ OccurringIndices);
+ SemaRef.MarkUsedTemplateParameters(DefaultArgs, /*Depth=*/0,
OccurringIndicesForSubsumption);
}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index c68ac12a88e8b..d87710d3cf140 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -10916,11 +10916,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (isFriend) {
// For friend function specializations, this is a dependent
// specialization if its semantic context is dependent, its
- // qualifier is dependent, its type is dependent, or its template-id is
- // dependent.
+ // type is dependent, or if its template-id is dependent.
isDependentSpecialization =
- DC->isDependentContext() || NewFD->getQualifier().isDependent() ||
- NewFD->getType()->isDependentType() ||
+ DC->isDependentContext() || NewFD->getType()->isDependentType() ||
(HasExplicitTemplateArgs &&
TemplateSpecializationType::
anyInstantiationDependentTemplateArguments(
@@ -12585,8 +12583,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// struct B { struct Y { ~Y(); }; using X = Y; };
// template struct A<B>;
if (NewFD->getFriendObjectKind() == Decl::FriendObjectKind::FOK_None ||
- (!Destructor->getFunctionObjectParameterType()->isDependentType() &&
- !Destructor->getDeclName().isDependentName())) {
+ !Destructor->getFunctionObjectParameterType()->isDependentType()) {
CanQualType ClassType =
Context.getCanonicalTagType(Destructor->getParent());
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 8d5ee07c5ad49..5c425a176ff41 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18127,153 +18127,31 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
return Decl;
}
-static QualType IgnorePackIndexing(QualType T) {
- if (const auto *PIT = dyn_cast<PackIndexingType>(T))
- return PIT->getPattern();
- return T;
-}
-
-static const TemplateSpecializationType *
-GetClassTemplateSpecializationType(ASTContext &Context, QualType T) {
- T = IgnorePackIndexing(T);
- if (const auto *ICNT = dyn_cast<InjectedClassNameType>(T))
- T = ICNT->getDecl()->getCanonicalTemplateSpecializationType(Context);
-
- const auto *TST = dyn_cast<TemplateSpecializationType>(T);
- if (!TST)
- return nullptr;
-
- TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
- if (!TD || isa<ClassTemplateDecl>(TD))
- return TST;
- return nullptr;
-}
-
-bool Sema::DiagnosePackIndexingInFriendNNS(SourceLocation Loc,
- NestedNameSpecifierLoc NNSLoc) {
- for (TypeLoc TL = NNSLoc.getAsTypeLoc(); TL;
- TL = TL.getPrefix().getAsTypeLoc()) {
- if (TL.getTypeLocClass() != TypeLoc::PackIndexing)
- continue;
-
- Diag(Loc, diag::err_pack_indexing_in_friend) << TL.getSourceRange();
- return true;
- }
- return false;
-}
-
-static void DiagnoseDependentFriendNotMember(Sema &S, SourceLocation Loc,
- NestedNameSpecifier NNS) {
- QualType T(NNS.getAsType(), 0);
- if (const auto *TST =
- dyn_cast<TemplateSpecializationType>(IgnorePackIndexing(T))) {
- if (isa_and_nonnull<TypeAliasTemplateDecl>(
- TST->getTemplateName().getAsTemplateDecl())) {
- S.Diag(Loc, diag::err_dependent_friend_not_member_of_template_spec)
- << NNS;
- return;
- }
- }
-
- if (NNS.getAsRecordDecl()) {
- S.Diag(Loc, diag::err_dependent_friend_not_member_of_template_spec) << NNS;
- } else {
- S.Diag(Loc, diag::err_dependent_friend_not_member);
- }
-}
-
-bool Sema::CheckDependentFriend(SourceLocation Loc,
- NestedNameSpecifierLoc NNSLoc,
- ArrayRef<TemplateParameterList *> TPLs,
- bool IsInstantiation) {
- NestedNameSpecifier NNS = NNSLoc.getNestedNameSpecifier();
- if (!NNS.isDependent() && !IsInstantiation)
- return false;
-
- assert(NNS.getKind() == NestedNameSpecifier::Kind::Type &&
- "nested-name-specifier of dependent friend must be a type");
-
- QualType T(NNS.getAsType(), 0);
- if (DiagnosePackIndexingInFriendNNS(Loc, NNSLoc))
- return true;
-
- const TemplateSpecializationType *TST =
- GetClassTemplateSpecializationType(Context, T);
- if (!TST) {
- DiagnoseDependentFriendNotMember(*this, Loc, NNS);
- return true;
- }
-
- if (TPLs.empty())
- return false;
-
- SmallVector<NamedDecl *, 4> UndeducedParameters;
- for (TemplateParameterList *Params : TPLs) {
- llvm::SmallBitVector UsedParameters(Params->size());
- MarkUsedTemplateParameters(TST->template_arguments(),
- /*OnlyDeduced=*/true, Params->getDepth(),
- UsedParameters);
-
- for (unsigned I = 0, N = UsedParameters.size(); I != N; ++I)
- if (!UsedParameters[I])
- UndeducedParameters.push_back(Params->getParam(I));
- }
-
- if (UndeducedParameters.empty())
- return false;
-
- Diag(Loc, diag::err_dependent_friend_undeduced_params)
- << (UndeducedParameters.size() > 1) << QualType(TST, 0);
-
- for (NamedDecl *Param : UndeducedParameters) {
- if (Param->getDeclName())
- Diag(Param->getLocation(), diag::note_non_deducible_parameter)
- << Param->getDeclName();
- else
- Diag(Param->getLocation(), diag::note_non_deducible_parameter)
- << "(anonymous)";
- }
-
- return true;
-}
-
DeclResult Sema::ActOnTemplatedFriendTag(
Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc,
CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
SourceLocation EllipsisLoc, const ParsedAttributesView &Attr,
- MultiTemplateParamsArg TempParamLists, TemplateIdAnnotation *TemplateId) {
+ MultiTemplateParamsArg TempParamLists) {
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
bool IsMemberSpecialization = false;
bool Invalid = false;
- TemplateParameterList *TemplateParams =
- MatchTemplateParametersToScopeSpecifier(TagLoc, NameLoc, SS, TemplateId,
- TempParamLists, /*friend*/ true,
- IsMemberSpecialization, Invalid);
- if (TemplateId) {
- if (Invalid)
- return true;
-
- if (TemplateParams) {
- Diag(NameLoc, diag::err_not_class_template_specialization) << 0;
- return true;
- }
- }
-
- if (TemplateParams) {
+ if (TemplateParameterList *TemplateParams =
+ MatchTemplateParametersToScopeSpecifier(
+ TagLoc, NameLoc, SS, nullptr, TempParamLists, /*friend*/ true,
+ IsMemberSpecialization, Invalid)) {
if (TemplateParams->size() > 0) {
+ // This is a declaration of a class template.
if (Invalid)
return true;
- if (SS.isEmpty() || !SS.getScopeRep().isDependent()) {
- DeclResult Result = CheckClassTemplate(
- S, TagSpec, TagUseKind::Friend, TagLoc, SS, Name, NameLoc, Attr,
- TemplateParams, AS_public, /*ModulePrivateLoc=*/SourceLocation(),
- FriendLoc, TempParamLists.size() - 1, TempParamLists.data(),
- IsMemberSpecialization);
- return Result.get();
- }
+ return CheckClassTemplate(S, TagSpec, TagUseKind::Friend, TagLoc, SS,
+ Name, NameLoc, Attr, TemplateParams, AS_public,
+ /*ModulePrivateLoc=*/SourceLocation(),
+ FriendLoc, TempParamLists.size() - 1,
+ TempParamLists.data(), IsMemberSpecialization)
+ .get();
} else {
// The "template<>" header is extraneous.
Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
@@ -18281,10 +18159,9 @@ DeclResult Sema::ActOnTemplatedFriendTag(
}
}
- if (Invalid)
- return true;
+ if (Invalid) return true;
- bool IsAllExplicitSpecializations =
+ bool isAllExplicitSpecializations =
llvm::all_of(TempParamLists, [](const TemplateParameterList *List) {
return List->size() == 0;
});
@@ -18295,7 +18172,7 @@ DeclResult Sema::ActOnTemplatedFriendTag(
// about the template header and build an appropriate non-templated
// friend. TODO: for source fidelity, remember the headers.
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
- if (!TemplateId && IsAllExplicitSpecializations) {
+ if (isAllExplicitSpecializations) {
if (SS.isEmpty()) {
bool Owned = false;
bool IsDependent = false;
@@ -18312,15 +18189,16 @@ DeclResult Sema::ActOnTemplatedFriendTag(
}
TypeSourceInfo *TSI = nullptr;
- ElaboratedTypeKeyword Keyword =
- TypeWithKeyword::getKeywordForTagTypeKind(Kind);
+ ElaboratedTypeKeyword Keyword
+ = TypeWithKeyword::getKeywordForTagTypeKind(Kind);
QualType T = CheckTypenameType(Keyword, TagLoc, QualifierLoc, *Name,
NameLoc, &TSI, /*DeducedTSTContext=*/true);
if (T.isNull())
return true;
- FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc, TSI,
- FriendLoc, EllipsisLoc);
+ FriendDecl *Friend =
+ FriendDecl::Create(Context, CurContext, NameLoc, TSI, FriendLoc,
+ EllipsisLoc, TempParamLists);
Friend->setAccess(AS_public);
CurContext->addDecl(Friend);
return Friend;
@@ -18328,86 +18206,43 @@ DeclResult Sema::ActOnTemplatedFriendTag(
assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?");
- ArrayRef<TemplateParameterList *> TPLs = TempParamLists;
- if (TemplateParams)
- TPLs = TPLs.drop_back();
- if (CheckDependentFriend(TagLoc, QualifierLoc, TPLs,
- /*IsInstantiation=*/false))
- return true;
-
- TypeSourceInfo *TSI = nullptr;
- if (TemplateId) {
- ASTTemplateArgsPtr ParsedArgs(TemplateId->getTemplateArgs(),
- TemplateId->NumArgs);
- TypeResult ParsedType = ActOnTagTemplateIdType(
- TagUseKind::Friend, static_cast<TypeSpecifierType>(TagSpec), TagLoc, SS,
- TemplateId->TemplateKWLoc, TemplateId->Template, NameLoc,
- TemplateId->LAngleLoc, ParsedArgs, TemplateId->RAngleLoc);
- if (ParsedType.isInvalid())
- return true;
-
- GetTypeFromParser(ParsedType.get(), &TSI);
- } else {
- ElaboratedTypeKeyword ETK = TypeWithKeyword::getKeywordForTagTypeKind(Kind);
- QualType T = Context.getDependentNameType(ETK, SS.getScopeRep(), Name);
- TSI = Context.CreateTypeSourceInfo(T);
-
- DependentNameTypeLoc TL = TSI->getTypeLoc().castAs<DependentNameTypeLoc>();
- TL.setElaboratedKeywordLoc(TagLoc);
- TL.setQualifierLoc(QualifierLoc);
- TL.setNameLoc(NameLoc);
- }
-
+ // 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(TSI->getTypeLoc(), Unexpanded);
- if (EllipsisLoc.isInvalid()) {
- if (DiagnoseUnexpandedParameterPack(TagLoc, TSI, UPPC_FriendDeclaration))
+ collectUnexpandedParameterPacks(QualifierLoc, Unexpanded);
+ unsigned FriendDeclDepth = TempParamLists.front()->getDepth();
+ for (UnexpandedParameterPack &U : Unexpanded) {
+ if (std::optional<std::pair<unsigned, unsigned>> DI = getDepthAndIndex(U);
+ DI && DI->first >= FriendDeclDepth) {
+ auto *ND = dyn_cast<NamedDecl *>(U.first);
+ if (!ND)
+ ND = cast<const TemplateTypeParmType *>(U.first)->getDecl();
+ Diag(U.second, diag::friend_template_decl_malformed_pack_expansion)
+ << ND->getDeclName() << SourceRange(SS.getBeginLoc(), EllipsisLoc);
return true;
- } else if (Unexpanded.empty()) {
- Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
- << TSI->getTypeLoc().getSourceRange();
- return true;
- } else {
- // CWG 2917: a pack expanded by a friend-type-specifier cannot have been
- // introduced by the template-declaration containing that specifier.
- if (!TempParamLists.empty()) {
- unsigned FriendDeclDepth = TempParamLists.front()->getDepth();
- for (UnexpandedParameterPack &U : Unexpanded) {
- if (std::optional<std::pair<unsigned, unsigned>> DI =
- getDepthAndIndex(U);
- DI && DI->first >= FriendDeclDepth) {
- auto *ND = dyn_cast<NamedDecl *>(U.first);
- if (!ND)
- ND = cast<const TemplateTypeParmType *>(U.first)->getDecl();
- Diag(U.second, diag::friend_template_decl_malformed_pack_expansion)
- << ND->getDeclName()
- << SourceRange(TSI->getTypeLoc().getBeginLoc(), EllipsisLoc);
- return true;
- }
- }
}
}
- FriendDecl *Friend;
- if (TempParamLists.empty())
- Friend = FriendDecl::Create(Context, CurContext, NameLoc, TSI, FriendLoc,
- EllipsisLoc);
- else {
- if (CheckTemplateDeclScope(S, TempParamLists.back()))
- return true;
-
- TemplateName FriendTemplate;
- if (TemplateParams)
- FriendTemplate = Context.getDependentTemplateName(
- {SS.getScopeRep(), Name, /*HasTemplateKeyword=*/false});
- Friend =
- FriendTemplateDecl::Create(Context, CurContext, NameLoc, TSI, FriendLoc,
- TempParamLists, EllipsisLoc, FriendTemplate);
- }
+ // Handle the case of a templated-scope friend class. e.g.
+ // template <class T> class A<T>::B;
+ // FIXME: we don't support these right now.
+ Diag(NameLoc, diag::warn_template_qualified_friend_unsupported)
+ << SS.getScopeRep() << SS.getRange() << cast<CXXRecordDecl>(CurContext);
+ ElaboratedTypeKeyword ETK = TypeWithKeyword::getKeywordForTagTypeKind(Kind);
+ QualType T = Context.getDependentNameType(ETK, SS.getScopeRep(), Name);
+ TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
+ DependentNameTypeLoc TL = TSI->getTypeLoc().castAs<DependentNameTypeLoc>();
+ TL.setElaboratedKeywordLoc(TagLoc);
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
+ TL.setNameLoc(NameLoc);
+ FriendDecl *Friend =
+ FriendDecl::Create(Context, CurContext, NameLoc, TSI, FriendLoc,
+ EllipsisLoc, TempParamLists);
Friend->setAccess(AS_public);
+ Friend->setUnsupportedFriend(true);
CurContext->addDecl(Friend);
-
return Friend;
}
@@ -18508,14 +18343,11 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// friend a member of an arbitrary specialization of your template).
Decl *D;
- if (!TempParams.empty()) {
- if (CheckTemplateDeclScope(S, TempParams.back()))
- return nullptr;
-
+ if (!TempParams.empty())
// TODO: Support variadic friend template decls?
- D = FriendTemplateDecl::Create(Context, CurContext, Loc, TSI, FriendLoc,
- TempParams, EllipsisLoc);
- } else
+ D = FriendTemplateDecl::Create(Context, CurContext, Loc, TempParams, TSI,
+ FriendLoc);
+ else
D = FriendDecl::Create(Context, CurContext, TSI->getTypeLoc().getBeginLoc(),
TSI, FriendLoc, EllipsisLoc);
@@ -18578,10 +18410,6 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
assert(NameInfo.getName());
- if (SS.isValid() && DiagnosePackIndexingInFriendNNS(
- NameInfo.getLoc(), SS.getWithLocInContext(Context)))
- return nullptr;
-
// Check for unexpanded parameter packs.
if (DiagnoseUnexpandedParameterPack(Loc, TInfo, UPPC_FriendDeclaration) ||
DiagnoseUnexpandedParameterPack(NameInfo, UPPC_FriendDeclaration) ||
@@ -18596,7 +18424,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
Kind == NestedNameSpecifier::Kind::Namespace;
if (IsNamespaceOrGlobal) {
Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def)
- << SS.getScopeRep();
+ << SS.getScopeRep() << FixItHint::CreateRemoval(SS.getRange());
SS.clear();
}
}
@@ -18707,8 +18535,11 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
diag::warn_cxx98_compat_friend_is_member :
diag::err_friend_is_member);
- // - There's a dependent scope specifier, in which case we use an
- // arbitrary context and wait for instantiation.
+ // - There's a scope specifier that does not match any template
+ // parameter lists, in which case we use some arbitrary context,
+ // create a method or method template, and wait for instantiation.
+ // - There's a scope specifier that does match some template
+ // parameter lists, which we don't handle right now.
} else {
DC = CurContext;
assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?");
@@ -18782,89 +18613,82 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
PushOnScopeChains(ND, EnclosingScope, /*AddToContext=*/ false);
}
- warnOnReservedIdentifier(ND);
+ FriendDecl *FrD = FriendDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(), ND,
+ DS.getFriendSpecLoc());
+ FrD->setAccess(AS_public);
+ CurContext->addDecl(FrD);
if (ND->isInvalidDecl()) {
- FriendDecl *Friend = FriendDecl::Create(
- Context, CurContext, D.getIdentifierLoc(), ND, DS.getFriendSpecLoc());
- Friend->setAccess(AS_public);
- if (!isa<FunctionTemplateDecl>(ND))
- Friend->setInvalidDecl();
- CurContext->addDecl(Friend);
- return ND;
- }
-
- FunctionDecl *FD = ND->getAsFunction();
- assert(FD && "Expected a function declaration!");
-
- ArrayRef<TemplateParameterList *> TPLs = FD->getTemplateParameterLists();
- if (!TPLs.empty() && SS.isValid() && CheckTemplateDeclScope(S, TPLs.back()))
- return nullptr;
+ FrD->setInvalidDecl();
+ } else {
+ if (DC->isRecord()) CheckFriendAccess(ND);
- FriendDecl *Friend;
- if (!TPLs.empty() && SS.isValid())
- Friend =
- FriendTemplateDecl::Create(Context, CurContext, D.getIdentifierLoc(),
- ND, DS.getFriendSpecLoc(), TPLs);
- else
- Friend = FriendDecl::Create(Context, CurContext, D.getIdentifierLoc(), ND,
- DS.getFriendSpecLoc());
+ FunctionDecl *FD;
+ if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
+ FD = FTD->getTemplatedDecl();
+ else
+ FD = cast<FunctionDecl>(ND);
+
+ // C++ [class.friend]p6:
+ // A function may be defined in a friend declaration of a class if and
+ // only if the class is a non-local class, and the function name is
+ // unqualified.
+ if (D.isFunctionDefinition()) {
+ // Qualified friend function definition.
+ if (SS.isNotEmpty()) {
+ // FIXME: We should only do this if the scope specifier names the
+ // innermost enclosing namespace; otherwise the fixit changes the
+ // meaning of the code.
+ SemaDiagnosticBuilder DB =
+ Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def);
+
+ DB << SS.getScopeRep();
+ if (DC->isFileContext())
+ DB << FixItHint::CreateRemoval(SS.getRange());
+
+ // Friend function defined in a local class.
+ } else if (FunctionContainingLocalClass) {
+ Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
+
+ // Per [basic.pre]p4, a template-id is not a name. Therefore, if we have
+ // a template-id, the function name is not unqualified because these is
+ // no name. While the wording requires some reading in-between the
+ // lines, GCC, MSVC, and EDG all consider a friend function
+ // specialization definitions to be de facto explicit specialization
+ // and diagnose them as such.
+ } else if (isTemplateId) {
+ Diag(NameInfo.getBeginLoc(), diag::err_friend_specialization_def);
+ }
+ }
- Friend->setAccess(AS_public);
- CurContext->addDecl(Friend);
+ // C++11 [dcl.fct.default]p4: If a friend declaration specifies a
+ // default argument expression, that declaration shall be a definition
+ // and shall be the only declaration of the function or function
+ // template in the translation unit.
+ if (functionDeclHasDefaultArgument(FD)) {
+ // We can't look at FD->getPreviousDecl() because it may not have been set
+ // if we're in a dependent context. If the function is known to be a
+ // redeclaration, we will have narrowed Previous down to the right decl.
+ if (D.isRedeclaration()) {
+ Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_redeclared);
+ Diag(Previous.getRepresentativeDecl()->getLocation(),
+ diag::note_previous_declaration);
+ } else if (!D.isFunctionDefinition())
+ Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_must_be_def);
+ }
- if (DC->isRecord())
- CheckFriendAccess(ND);
-
- if (!TemplateParams.empty() && SS.isValid() &&
- CheckDependentFriend(NameInfo.getLoc(), SS.getWithLocInContext(Context),
- FD->getTemplateParameterLists(),
- /*IsInstantiation=*/false))
- return ND;
-
- // C++ [class.friend]p6:
- // A function may be defined in a friend declaration of a class if and
- // only if the class is a non-local class, and the function name is
- // unqualified.
- if (D.isFunctionDefinition()) {
- // Qualified friend function definition.
- if (SS.isNotEmpty()) {
- SemaDiagnosticBuilder DB =
- Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def);
-
- DB << SS.getScopeRep();
-
- // Friend function defined in a local class.
- } else if (FunctionContainingLocalClass) {
- Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class);
-
- // Per [basic.pre]p4, a template-id is not a name. Therefore, if we have
- // a template-id, the function name is not unqualified because these is
- // no name. While the wording requires some reading in-between the
- // lines, GCC, MSVC, and EDG all consider a friend function
- // specialization definitions to be de facto explicit specialization
- // and diagnose them as such.
- } else if (isTemplateId) {
- Diag(NameInfo.getBeginLoc(), diag::err_friend_specialization_def);
- }
- }
-
- // C++11 [dcl.fct.default]p4: If a friend declaration specifies a
- // default argument expression, that declaration shall be a definition
- // and shall be the only declaration of the function or function
- // template in the translation unit.
- if (functionDeclHasDefaultArgument(FD)) {
- // We can't look at FD->getPreviousDecl() because it may not have been set
- // if we're in a dependent context. If the function is known to be a
- // redeclaration, we will have narrowed Previous down to the right decl.
- if (D.isRedeclaration()) {
- Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_redeclared);
- Diag(Previous.getRepresentativeDecl()->getLocation(),
- diag::note_previous_declaration);
- } else if (!D.isFunctionDefinition())
- Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_must_be_def);
+ // Mark templated-scope function declarations as unsupported.
+ if (!FD->getTemplateParameterLists().empty() && SS.isValid()) {
+ Diag(FD->getLocation(), diag::warn_template_qualified_friend_unsupported)
+ << SS.getScopeRep() << SS.getRange()
+ << cast<CXXRecordDecl>(CurContext);
+ FrD->setUnsupportedFriend(true);
+ }
}
+ warnOnReservedIdentifier(ND);
+
return ND;
}
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index daa4bb5234b7b..d41137ddc85d5 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -655,8 +655,7 @@ static bool CheckEquivalentExceptionSpecImpl(
return true;
}
- if (DiagID.getDiagID() != 0)
- S.Diag(NewLoc, DiagID);
+ S.Diag(NewLoc, DiagID);
if (NoteID.getDiagID() != 0 && OldLoc.isValid())
S.Diag(OldLoc, NoteID);
return true;
@@ -668,7 +667,7 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
SourceLocation OldLoc,
const FunctionProtoType *New,
SourceLocation NewLoc) {
- if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus17)
+ if (!getLangOpts().CXXExceptions)
return false;
return CheckEquivalentExceptionSpecImpl(*this, DiagID, NoteID, Old, OldLoc,
New, NewLoc);
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 81bc6c68f377d..97744b6e8836b 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12420,9 +12420,8 @@ static TemplateDecl *getDescribedTemplate(Decl *Templated) {
/// Diagnose a failed template-argument deduction.
static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
DeductionFailureInfo &DeductionFailure,
- unsigned NumArgs, bool TakingCandidateAddress,
- TemplateSpecCandidateSetKind CandidateSetKind =
- TemplateSpecCandidateSetKind::Normal) {
+ unsigned NumArgs,
+ bool TakingCandidateAddress) {
TemplateParameter Param = DeductionFailure.getTemplateParameter();
NamedDecl *ParamD;
(ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) ||
@@ -12669,10 +12668,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
// name for types, not decls.
// Ideally, this should folded into the diagnostic printer.
S.Diag(Templated->getLocation(),
- CandidateSetKind ==
- TemplateSpecCandidateSetKind::FriendTemplate
- ? diag::note_friend_template_non_deduced_mismatch_qualified
- : diag::note_ovl_candidate_non_deduced_mismatch_qualified)
+ diag::note_ovl_candidate_non_deduced_mismatch_qualified)
<< FirstTN.getAsTemplateDecl() << SecondTN.getAsTemplateDecl();
return;
}
@@ -12688,9 +12684,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
// diagnostic that mentions 'auto' and lambda in addition to
// (or instead of?) the canonical template type parameters.
S.Diag(Templated->getLocation(),
- CandidateSetKind == TemplateSpecCandidateSetKind::FriendTemplate
- ? diag::note_friend_template_non_deduced_mismatch
- : diag::note_ovl_candidate_non_deduced_mismatch)
+ diag::note_ovl_candidate_non_deduced_mismatch)
<< FirstTA << SecondTA;
return;
}
@@ -13641,12 +13635,10 @@ struct CompareTemplateSpecCandidatesForDisplay {
/// Diagnose a template argument deduction failure.
/// We are treating these failures as overload failures due to bad
/// deductions.
-void TemplateSpecCandidate::NoteDeductionFailure(
- Sema &S, bool ForTakingAddress,
- TemplateSpecCandidateSetKind CandidateSetKind) {
+void TemplateSpecCandidate::NoteDeductionFailure(Sema &S,
+ bool ForTakingAddress) {
DiagnoseBadDeduction(S, FoundDecl, Specialization, // pattern
- DeductionFailure, /*NumArgs=*/0, ForTakingAddress,
- CandidateSetKind);
+ DeductionFailure, /*NumArgs=*/0, ForTakingAddress);
}
void TemplateSpecCandidateSet::destroyCandidates() {
@@ -13698,7 +13690,7 @@ void TemplateSpecCandidateSet::NoteCandidates(Sema &S, SourceLocation Loc) {
assert(Cand->Specialization &&
"Non-matching built-in candidates are not added to Cands.");
- Cand->NoteDeductionFailure(S, ForTakingAddress, CandidateSetKind);
+ Cand->NoteDeductionFailure(S, ForTakingAddress);
}
if (I != E)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index dff681454ae5a..643392833759d 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1977,9 +1977,14 @@ DeclResult Sema::CheckClassTemplate(
if (SS.isNotEmpty() && !SS.isInvalid()) {
SemanticContext = computeDeclContext(SS, true);
if (!SemanticContext) {
- Diag(NameLoc, diag::err_template_qualified_declarator_no_match)
+ // FIXME: Horrible, horrible hack! We can't currently represent this
+ // in the AST, and historically we have just ignored such friend
+ // class templates, so don't complain here.
+ Diag(NameLoc, TUK == TagUseKind::Friend
+ ? diag::warn_template_qualified_friend_ignored
+ : diag::err_template_qualified_declarator_no_match)
<< SS.getScopeRep() << SS.getRange();
- return true;
+ return TUK != TagUseKind::Friend;
}
if (RequireCompleteDeclContext(SS, SemanticContext))
@@ -3048,8 +3053,6 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
ExpectedTemplateParams = Template->getTemplateParameters();
NeedNonemptyTemplateHeader = true;
- } else if (Name.getAsDependentTemplateName()) {
- NeedNonemptyTemplateHeader = true;
} else if (Name.getAsDeducedTemplateName()) {
// FIXME: We actually could/should check the template arguments here
// against the corresponding template parameter list.
@@ -9578,15 +9581,6 @@ bool Sema::CheckDependentFunctionTemplateSpecialization(
bool IsFriend = FD->getFriendObjectKind() != Decl::FOK_None;
if (Previous.empty()) {
- NestedNameSpecifier FriendQualifier = FD->getQualifier();
- if (IsFriend && FriendQualifier.isDependent() &&
- FriendQualifier.getKind() == NestedNameSpecifier::Kind::Type &&
- FriendQualifier.getAsType()->getAs<TemplateSpecializationType>()) {
- FD->setDependentTemplateSpecialization(
- Context, Previous.asUnresolvedSet(), ExplicitTemplateArgs);
- return false;
- }
-
Diag(FD->getLocation(), diag::err_dependent_function_template_spec_no_match)
<< IsFriend;
for (auto &P : DiscardedCandidates)
@@ -11209,10 +11203,6 @@ TypeResult Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (!NNS)
return true;
- if (TUK == TagUseKind::Friend &&
- DiagnosePackIndexingInFriendNNS(NameLoc, SS.getWithLocInContext(Context)))
- return true;
-
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
if (TUK == TagUseKind::Declaration || TUK == TagUseKind::Definition) {
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index c57a090a8553e..3c45806c47a6e 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3225,12 +3225,42 @@ CheckDeducedArgumentConstraints(Sema &S, NamedDecl *Template,
return TemplateDeductionResult::Success;
}
-static TemplateDeductionResult CheckDeducedTemplateArgumentList(
- Sema &S, TemplateDecl *Template, ArrayRef<TemplateArgumentLoc> Ps,
- ArrayRef<TemplateArgument> As, const MultiLevelTemplateArgumentList &MLTAL,
- TemplateDeductionInfo &Info) {
+/// Complete template argument deduction.
+static TemplateDeductionResult FinishTemplateArgumentDeduction(
+ Sema &S, NamedDecl *Entity, TemplateParameterList *EntityTPL,
+ TemplateDecl *Template, bool PartialOrdering,
+ ArrayRef<TemplateArgumentLoc> Ps, ArrayRef<TemplateArgument> As,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ TemplateDeductionInfo &Info, bool CopyDeducedArgs) {
+ Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Entity));
+
+ // C++ [temp.deduct.type]p2:
+ // [...] or if any template argument remains neither deduced nor
+ // explicitly specified, template argument deduction fails.
+ Sema::CheckTemplateArgumentInfo CTAI(PartialOrdering);
+ if (auto Result = ConvertDeducedTemplateArguments(
+ S, Entity, EntityTPL, /*IsDeduced=*/PartialOrdering, Deduced, Info,
+ CTAI,
+ /*CurrentInstantiationScope=*/nullptr,
+ /*NumAlreadyConverted=*/0U, /*IsIncomplete=*/nullptr);
+ Result != TemplateDeductionResult::Success)
+ return Result;
+
+ if (CopyDeducedArgs) {
+ // Form the template argument list from the deduced template arguments.
+ TemplateArgumentList *SugaredDeducedArgumentList =
+ TemplateArgumentList::CreateCopy(S.Context, CTAI.SugaredConverted);
+ TemplateArgumentList *CanonicalDeducedArgumentList =
+ TemplateArgumentList::CreateCopy(S.Context, CTAI.CanonicalConverted);
+ Info.reset(SugaredDeducedArgumentList, CanonicalDeducedArgumentList);
+ }
+
TemplateParameterList *TPL = Template->getTemplateParameters();
TemplateArgumentListInfo InstArgs(TPL->getLAngleLoc(), TPL->getRAngleLoc());
+ MultiLevelTemplateArgumentList MLTAL(Entity, CTAI.SugaredConverted,
+ /*Final=*/true);
+ MLTAL.addOuterRetainedLevels(TPL->getDepth());
+
if (S.SubstTemplateArguments(Ps, MLTAL, InstArgs)) {
unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx;
if (ParamIdx >= TPL->size())
@@ -3306,46 +3336,6 @@ static TemplateDeductionResult CheckDeducedTemplateArgumentList(
}
assert(PsStack.empty());
assert(AsStack.empty());
- return TemplateDeductionResult::Success;
-}
-
-/// Complete template argument deduction.
-static TemplateDeductionResult FinishTemplateArgumentDeduction(
- Sema &S, NamedDecl *Entity, TemplateParameterList *EntityTPL,
- TemplateDecl *Template, bool PartialOrdering,
- ArrayRef<TemplateArgumentLoc> Ps, ArrayRef<TemplateArgument> As,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- TemplateDeductionInfo &Info, bool CopyDeducedArgs) {
- Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Entity));
-
- // C++ [temp.deduct.type]p2:
- // [...] or if any template argument remains neither deduced nor
- // explicitly specified, template argument deduction fails.
- Sema::CheckTemplateArgumentInfo CTAI(PartialOrdering);
- if (auto Result = ConvertDeducedTemplateArguments(
- S, Entity, EntityTPL, /*IsDeduced=*/PartialOrdering, Deduced, Info,
- CTAI,
- /*CurrentInstantiationScope=*/nullptr,
- /*NumAlreadyConverted=*/0U, /*IsIncomplete=*/nullptr);
- Result != TemplateDeductionResult::Success)
- return Result;
-
- if (CopyDeducedArgs) {
- // Form the template argument list from the deduced template arguments.
- TemplateArgumentList *SugaredDeducedArgumentList =
- TemplateArgumentList::CreateCopy(S.Context, CTAI.SugaredConverted);
- TemplateArgumentList *CanonicalDeducedArgumentList =
- TemplateArgumentList::CreateCopy(S.Context, CTAI.CanonicalConverted);
- Info.reset(SugaredDeducedArgumentList, CanonicalDeducedArgumentList);
- }
-
- MultiLevelTemplateArgumentList MLTAL(Entity, CTAI.SugaredConverted,
- /*Final=*/true);
- MLTAL.addOuterRetainedLevels(Template->getTemplateParameters()->getDepth());
- if (auto Result =
- CheckDeducedTemplateArgumentList(S, Template, Ps, As, MLTAL, Info);
- Result != TemplateDeductionResult::Success)
- return Result;
if (!PartialOrdering) {
if (auto Result = CheckDeducedArgumentConstraints(
@@ -4122,147 +4112,6 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
return TemplateDeductionResult::Success;
}
-static void AddFriendTemplateDeductionCandidate(
- Sema &S, TemplateDecl *TD, TemplateDeductionInfo &Info,
- TemplateDeductionResult Result, TemplateSpecCandidateSet *FailedTSC) {
- if (!FailedTSC)
- return;
-
- Decl *TemplatedDecl = TD->getTemplatedDecl();
- for (TemplateSpecCandidate &Candidate : *FailedTSC) {
- if (Candidate.Specialization &&
- declaresSameEntity(Candidate.Specialization, TemplatedDecl))
- return;
- }
-
- FailedTSC->addCandidate().set(
- DeclAccessPair::make(TD, AS_public), TemplatedDecl,
- MakeDeductionFailureInfo(S.Context, Result, Info));
-}
-
-bool Sema::DeduceTemplateArguments(
- FriendTemplateDecl *FTD, ClassTemplateDecl *PatternCTD,
- ClassTemplateDecl *CandidateCTD, ArrayRef<TemplateParameterList *> TPLs,
- ArrayRef<TemplateArgument> PatternArgs,
- ArrayRef<TemplateArgument> CandidateArgs, SourceLocation Loc,
- TemplateSpecCandidateSet *FailedTSC,
- MultiLevelTemplateArgumentList &DeducedArgs) {
- EnterExpressionEvaluationContext Unevaluated(
- *this, ExpressionEvaluationContext::Unevaluated);
- ContextRAII SavedContext(*this, FTD->getDeclContext());
- LocalInstantiationScope InstantiationScope(*this);
- InstantiatingTemplate Inst(*this, Loc, FTD);
- if (Inst.isInvalid()) {
- TemplateDeductionInfo Info(Loc);
- AddFriendTemplateDeductionCandidate(
- *this, PatternCTD, Info, TemplateDeductionResult::InstantiationDepth,
- FailedTSC);
- return false;
- }
-
- SmallVector<TemplateArgumentList *, 2> DeducedArgLists;
- DeducedArgLists.reserve(TPLs.size());
- for (TemplateParameterList *Params : TPLs) {
- TemplateDeductionInfo Info(Loc, Params->getDepth());
- SFINAETrap Trap(*this, Info);
- SmallVector<DeducedTemplateArgument, 4> Deduced(Params->size());
- TemplateDeductionResult Result = DeduceTemplateArguments(
- Params, PatternArgs, CandidateArgs, Info, Deduced,
- /*NumberOfArgumentsMustMatch=*/false);
-
- CheckTemplateArgumentInfo CTAI;
- bool IsIncomplete = false;
- if (Result == TemplateDeductionResult::Success)
- Result = ConvertDeducedTemplateArguments(
- *this, PatternCTD, Params, /*IsDeduced=*/false, Deduced, Info, CTAI,
- &InstantiationScope, /*NumAlreadyConverted=*/0, &IsIncomplete);
- if (Result == TemplateDeductionResult::Success && IsIncomplete) {
- for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
- if (!Deduced[I].isNull())
- continue;
- Info.Param = makeTemplateParameter(Params->getParam(I));
- break;
- }
- Info.reset(
- TemplateArgumentList::CreateCopy(Context, CTAI.SugaredConverted),
- TemplateArgumentList::CreateCopy(Context, CTAI.CanonicalConverted));
- Result = TemplateDeductionResult::Incomplete;
- }
- if (Result == TemplateDeductionResult::Success && Trap.hasErrorOccurred())
- Result = TemplateDeductionResult::SubstitutionFailure;
- if (Result != TemplateDeductionResult::Success) {
- AddFriendTemplateDeductionCandidate(*this, PatternCTD, Info, Result,
- FailedTSC);
- return false;
- }
-
- DeducedArgLists.push_back(
- TemplateArgumentList::CreateCopy(Context, CTAI.SugaredConverted));
- }
-
- for (TemplateArgumentList *Args : llvm::reverse(DeducedArgLists))
- DeducedArgs.addOuterTemplateArguments(FTD, Args->asArray(),
- /*Final=*/true);
- if (!TPLs.empty())
- DeducedArgs.addOuterRetainedLevels(TPLs.front()->getDepth());
-
- if (DeducedArgs.isAnyArgInstantiationDependent() &&
- llvm::any_of(TPLs, [](TemplateParameterList *Params) {
- return Params->hasAssociatedConstraints();
- }))
- return false;
-
- SmallVector<TemplateArgumentLoc, 8> PatternArgLocs;
- PatternArgLocs.reserve(PatternArgs.size());
- for (const TemplateArgument &Arg : PatternArgs)
- PatternArgLocs.push_back(
- getTrivialTemplateArgumentLoc(Arg, QualType(), Loc));
-
- {
- TemplateDeductionInfo Info(Loc);
- SFINAETrap Trap(*this, Info);
- TemplateDeductionResult Result = CheckDeducedTemplateArgumentList(
- *this, CandidateCTD, PatternArgLocs, CandidateArgs, DeducedArgs, Info);
- if (Result == TemplateDeductionResult::Success && Trap.hasErrorOccurred())
- Result = TemplateDeductionResult::SubstitutionFailure;
- if (Result != TemplateDeductionResult::Success) {
- AddFriendTemplateDeductionCandidate(*this, PatternCTD, Info, Result,
- FailedTSC);
- return false;
- }
- }
-
- for (TemplateParameterList *Params : TPLs) {
- SmallVector<AssociatedConstraint, 3> Constraints;
- Params->getAssociatedConstraints(Constraints);
- if (Constraints.empty())
- continue;
-
- TemplateDeductionInfo Info(Loc, Params->getDepth());
- SFINAETrap Trap(*this, Info);
- if (CheckConstraintSatisfaction(PatternCTD, Constraints, DeducedArgs,
- SourceRange(Loc),
- Info.AssociatedConstraintsSatisfaction) ||
- !Info.AssociatedConstraintsSatisfaction.IsSatisfied ||
- Trap.hasErrorOccurred()) {
- SmallVector<TemplateArgument, 4> CanonicalCandidateArgs;
- CanonicalCandidateArgs.reserve(CandidateArgs.size());
- for (const TemplateArgument &Arg : CandidateArgs)
- CanonicalCandidateArgs.push_back(
- Context.getCanonicalTemplateArgument(Arg));
- Info.reset(
- TemplateArgumentList::CreateCopy(Context, CandidateArgs),
- TemplateArgumentList::CreateCopy(Context, CanonicalCandidateArgs));
- AddFriendTemplateDeductionCandidate(
- *this, PatternCTD, Info,
- TemplateDeductionResult::ConstraintsNotSatisfied, FailedTSC);
- return false;
- }
- }
-
- return true;
-}
-
/// Gets the type of a function for template-argument-deducton
/// purposes when it's considered as part of an overload set.
static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R,
@@ -7347,14 +7196,11 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
}
void Sema::MarkUsedTemplateParameters(ArrayRef<TemplateArgument> TemplateArgs,
- bool OnlyDeduced, unsigned Depth,
+ unsigned Depth,
llvm::SmallBitVector &Used) {
- if (OnlyDeduced && hasPackExpansionBeforeEnd(TemplateArgs))
- return;
-
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
- ::MarkUsedTemplateParameters(Context, TemplateArgs[I], OnlyDeduced, Depth,
- Used);
+ ::MarkUsedTemplateParameters(Context, TemplateArgs[I],
+ /*OnlyDeduced=*/false, Depth, Used);
}
void Sema::MarkUsedTemplateParameters(
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 40c5a6181c51d..3f37b59807f85 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -889,15 +889,14 @@ SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
ArrayRef<TemplateArgument> DeducedArgs) {
llvm::SmallBitVector ReferencedTemplateParams(TemplateParamsList->size());
- SemaRef.MarkUsedTemplateParameters(DeducedArgs, /*OnlyDeduced=*/false,
- TemplateParamsList->getDepth(),
- ReferencedTemplateParams);
+ SemaRef.MarkUsedTemplateParameters(
+ DeducedArgs, TemplateParamsList->getDepth(), ReferencedTemplateParams);
auto MarkDefaultArgs = [&](auto *Param) {
if (!Param->hasDefaultArgument())
return;
SemaRef.MarkUsedTemplateParameters(
- Param->getDefaultArgument().getArgument(), /*OnlyDeduced=*/false,
+ Param->getDefaultArgument().getArgument(),
TemplateParamsList->getDepth(), ReferencedTemplateParams);
};
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index a21f65f687568..79d106168e9d0 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2006,247 +2006,68 @@ Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
return IndirectField;
}
-static std::optional<TemplateName>
-LookupFriendTemplateName(Sema &SemaRef, NestedNameSpecifierLoc QualifierLoc,
- DeclarationName Name, SourceLocation NameLoc,
- bool HasTemplateKeyword, bool RequireClassTemplate) {
- if (!QualifierLoc)
- return TemplateName();
-
- CXXScopeSpec SS;
- SS.Adopt(QualifierLoc);
-
- DeclContext *DC = SemaRef.computeDeclContext(SS, /*EnteringContext=*/true);
- if (!DC) {
- if (QualifierLoc.getNestedNameSpecifier().isDependent())
- return TemplateName();
- return std::nullopt;
- }
-
- bool IsDependentContext = DC->isDependentContext();
- if (!IsDependentContext && SemaRef.RequireCompleteDeclContext(SS, DC))
- return std::nullopt;
-
- LookupResult Result(SemaRef, Name, NameLoc, Sema::LookupOrdinaryName,
- SemaRef.forRedeclarationInCurContext());
- if (!SemaRef.LookupQualifiedName(Result, DC)) {
- if (RequireClassTemplate && !IsDependentContext) {
- SemaRef.Diag(NameLoc, diag::err_no_member_template)
- << Name << DC << QualifierLoc.getSourceRange();
- return std::nullopt;
- }
- return TemplateName();
- }
-
- if (Result.isAmbiguous())
- return std::nullopt;
-
- auto *CTD = Result.getAsSingle<ClassTemplateDecl>();
- if (!CTD) {
- if (RequireClassTemplate && !IsDependentContext) {
- SemaRef.Diag(NameLoc, diag::err_redefinition_
diff erent_kind) << Name;
- SemaRef.Diag(
- Result.getRepresentativeDecl()->getUnderlyingDecl()->getLocation(),
- diag::note_previous_definition);
- return std::nullopt;
- }
- return TemplateName();
- }
-
- auto *FoundUsingShadow =
- dyn_cast<UsingShadowDecl>(Result.getRepresentativeDecl());
-
- return SemaRef.Context.getQualifiedTemplateName(
- QualifierLoc.getNestedNameSpecifier(), HasTemplateKeyword,
- FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(CTD));
-}
-
-TypeSourceInfo *
-Sema::SubstFriendType(TypeSourceInfo *TSI,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation Loc, DeclarationName Entity) {
- TemplateSpecializationTypeLoc TSTL =
- TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
- NestedNameSpecifierLoc QualifierLoc =
- TSTL ? TSTL.getQualifierLoc() : NestedNameSpecifierLoc();
- if (!TSTL || !QualifierLoc ||
- !QualifierLoc.getNestedNameSpecifier().isDependent())
- return SubstType(TSI, TemplateArgs, Loc, Entity);
-
- const auto *FriendTST = TSTL.getTypePtr();
- auto *FriendCTD = dyn_cast_or_null<ClassTemplateDecl>(
- FriendTST->getTemplateName().getAsTemplateDecl());
- if (!FriendCTD)
- return SubstType(TSI, TemplateArgs, Loc, Entity);
-
- QualifierLoc = SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs);
- if (!QualifierLoc)
- return nullptr;
-
- std::optional<TemplateName> InstTemplate = LookupFriendTemplateName(
- *this, QualifierLoc, FriendCTD->getDeclName(), TSTL.getTemplateNameLoc(),
- TSTL.getTemplateKeywordLoc().isValid(),
- /*RequireClassTemplate=*/false);
- if (!InstTemplate)
- return nullptr;
- if (InstTemplate->isNull())
- return SubstType(TSI, TemplateArgs, Loc, Entity);
-
- SmallVector<TemplateArgumentLoc, 4> FriendArgLocs;
- for (unsigned I = 0, N = TSTL.getNumArgs(); I != N; ++I)
- FriendArgLocs.push_back(TSTL.getArgLoc(I));
-
- TemplateArgumentListInfo InstArgs(TSTL.getLAngleLoc(), TSTL.getRAngleLoc());
- if (SubstTemplateArguments(FriendArgLocs, TemplateArgs, InstArgs))
- return nullptr;
-
- QualType InstTy =
- CheckTemplateIdType(FriendTST->getKeyword(), *InstTemplate,
- TSTL.getTemplateNameLoc(), InstArgs,
- /*Scope=*/nullptr, /*ForNestedNameSpecifier=*/false);
- if (InstTy.isNull())
- return nullptr;
-
- TypeLocBuilder TLB;
- TLB.push<TemplateSpecializationTypeLoc>(InstTy).set(
- TSTL.getElaboratedKeywordLoc(), QualifierLoc,
- TSTL.getTemplateKeywordLoc(), TSTL.getTemplateNameLoc(), InstArgs);
- return TLB.getTypeSourceInfo(Context, InstTy);
-}
-
-struct SubstitutedFriend {
- TypeSourceInfo *TypeInfo = nullptr;
- TemplateName TemplateName;
-
- bool empty() const { return !TypeInfo && TemplateName.isNull(); }
-};
-
-static std::optional<SubstitutedFriend>
-SubstFriendTemplateType(Sema &SemaRef, TypeSourceInfo *TSI,
- TemplateName FriendTemplate,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation Loc, DeclarationName Entity) {
- NestedNameSpecifierLoc QualifierLoc = TSI->getTypeLoc().getPrefix();
- NestedNameSpecifierLoc InstQualifierLoc = QualifierLoc;
- if (QualifierLoc && QualifierLoc.getNestedNameSpecifier().isDependent()) {
- InstQualifierLoc =
- SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs);
- if (!InstQualifierLoc ||
- SemaRef.CheckDependentFriend(Loc, InstQualifierLoc, /*TPLs=*/{},
- /*IsInstantiation=*/true))
- return std::nullopt;
- }
-
- TemplateName InstFriendTemplate;
- if (!FriendTemplate.isNull()) {
- auto DNTL = TSI->getTypeLoc().getAs<DependentNameTypeLoc>();
- assert(DNTL && "friend class template must have a dependent name type");
-
- std::optional<TemplateName> InstTemplate = LookupFriendTemplateName(
- SemaRef, InstQualifierLoc, DNTL.getTypePtr()->getIdentifier(),
- DNTL.getNameLoc(), /*HasTemplateKeyword=*/false,
- /*RequireClassTemplate=*/true);
- if (!InstTemplate)
- return std::nullopt;
- if (!InstTemplate->isNull())
- return SubstitutedFriend{nullptr, *InstTemplate};
-
- auto *DTN = FriendTemplate.getAsDependentTemplateName();
- assert(DTN && "unresolved friend template must have a dependent name");
- InstFriendTemplate = SemaRef.Context.getDependentTemplateName(
- {InstQualifierLoc.getNestedNameSpecifier(), DTN->getName(),
- DTN->hasTemplateKeyword()});
- }
-
- TypeSourceInfo *InstType =
- SemaRef.SubstFriendType(TSI, TemplateArgs, Loc, Entity);
- if (!InstType)
- return std::nullopt;
- return SubstitutedFriend{InstType, InstFriendTemplate};
-}
-
-bool TemplateDeclInstantiator::InstantiateFriendPackExpansion(FriendDecl *D) {
- TypeSourceInfo *TSI = D->getFriendType();
- assert(TSI && "friend pack expansion must name a type");
-
- const auto *FTD = dyn_cast<FriendTemplateDecl>(D);
- ArrayRef<TemplateParameterList *> TPLs;
- if (FTD)
- TPLs = FTD->getTemplateParameterLists();
-
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- SemaRef.collectUnexpandedParameterPacks(TSI->getTypeLoc(), Unexpanded);
- assert(!Unexpanded.empty() && "Pack expansion without packs");
-
- bool ShouldExpand = true;
- bool RetainExpansion = false;
- UnsignedOrNone NumExpansions = std::nullopt;
- if (SemaRef.CheckParameterPacksForExpansion(
- D->getEllipsisLoc(), D->getSourceRange(), Unexpanded, TemplateArgs,
- /*FailOnPackProducingTemplates=*/true, ShouldExpand, RetainExpansion,
- NumExpansions))
- return true;
-
- assert(!RetainExpansion &&
- "should never retain an expansion for a friend declaration");
-
- if (!ShouldExpand)
- return false;
-
- for (unsigned I = 0; I != *NumExpansions; I++) {
- Sema::ArgPackSubstIndexRAII SubstIndex(SemaRef, I);
- LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
- SmallVector<TemplateParameterList *, 1> InstTPLs;
- if (SubstTemplateParameterLists(TPLs, InstTPLs))
- return true;
-
- std::optional<SubstitutedFriend> InstFriend;
- if (FTD)
- InstFriend = SubstFriendTemplateType(
- SemaRef, TSI, FTD->getFriendTemplateName(), TemplateArgs,
- D->getEllipsisLoc(), DeclarationName());
- else if (TypeSourceInfo *InstType = SemaRef.SubstFriendType(
- TSI, TemplateArgs, D->getEllipsisLoc(), DeclarationName()))
- InstFriend = SubstitutedFriend{InstType, {}};
- if (!InstFriend || InstFriend->empty())
- return true;
-
- FriendDecl *FD;
- if (FTD) {
- FriendDecl::FriendUnion ToFriend =
- InstFriend->TypeInfo ? FriendDecl::FriendUnion(InstFriend->TypeInfo)
- : FriendDecl::FriendUnion();
- FD = FriendTemplateDecl::Create(
- SemaRef.Context, Owner, D->getLocation(), ToFriend, D->getFriendLoc(),
- InstTPLs, /*EllipsisLoc=*/{}, InstFriend->TemplateName);
+Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
+ // Handle friend type expressions by simply substituting template
+ // parameters into the pattern type and checking the result.
+ if (TypeSourceInfo *Ty = D->getFriendType()) {
+ TypeSourceInfo *InstTy;
+ // If this is an unsupported friend, don't bother substituting template
+ // arguments into it. The actual type referred to won't be used by any
+ // parts of Clang, and may not be valid for instantiating. Just use the
+ // same info for the instantiated friend.
+ if (D->isUnsupportedFriend()) {
+ InstTy = Ty;
} else {
- assert(InstTPLs.empty() && "unexpected template parameter lists");
- assert(InstFriend->TemplateName.isNull() &&
- "non-template friend resolved to a class template");
- FD = FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- InstFriend->TypeInfo, D->getFriendLoc());
- }
-
- FD->setAccess(AS_public);
- Owner->addDecl(FD);
- }
+ 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;
+ UnsignedOrNone NumExpansions = std::nullopt;
+ if (SemaRef.CheckParameterPacksForExpansion(
+ D->getEllipsisLoc(), D->getSourceRange(), Unexpanded,
+ TemplateArgs, /*FailOnPackProducingTemplates=*/true,
+ ShouldExpand, RetainExpansion, NumExpansions))
+ return nullptr;
- return true;
-}
+ 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::ArgPackSubstIndexRAII 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);
+ }
-Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
- if (TypeSourceInfo *Ty = D->getFriendType()) {
- if (D->isPackExpansion() && InstantiateFriendPackExpansion(D))
- return nullptr;
+ // Just drop this node; we have no use for it anymore.
+ return nullptr;
+ }
+ }
- TypeSourceInfo *InstTy = SemaRef.SubstFriendType(
- Ty, TemplateArgs, D->getLocation(), DeclarationName());
+ InstTy = SemaRef.SubstType(Ty, TemplateArgs, D->getLocation(),
+ DeclarationName());
+ }
if (!InstTy)
return nullptr;
FriendDecl *FD = FriendDecl::Create(
SemaRef.Context, Owner, D->getLocation(), InstTy, D->getFriendLoc());
FD->setAccess(AS_public);
+ FD->setUnsupportedFriend(D->isUnsupportedFriend());
Owner->addDecl(FD);
return FD;
}
@@ -2265,6 +2086,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(),
cast<NamedDecl>(NewND), D->getFriendLoc());
FD->setAccess(AS_public);
+ FD->setUnsupportedFriend(D->isUnsupportedFriend());
Owner->addDecl(FD);
return FD;
}
@@ -3029,12 +2851,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
if (!QualifierLoc)
return nullptr;
}
- if (isFriend &&
- (FunctionTemplate || !D->getTemplateParameterLists().empty()) &&
- D->getQualifier().isDependent() &&
- SemaRef.CheckDependentFriend(D->getLocation(), QualifierLoc,
- /*TPLs=*/{}, /*IsInstantiation=*/true))
- return nullptr;
AssociatedConstraint TrailingRequiresClause = D->getTrailingRequiresClause();
@@ -3449,23 +3265,17 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
if (!QualifierLoc)
return nullptr;
}
- if (isFriend &&
- (FunctionTemplate || !D->getTemplateParameterLists().empty()) &&
- D->getQualifier().isDependent() &&
- SemaRef.CheckDependentFriend(D->getLocation(), QualifierLoc,
- /*TPLs=*/{}, /*IsInstantiation=*/true))
- return nullptr;
DeclContext *DC = Owner;
if (isFriend) {
- if (QualifierLoc && !QualifierLoc.getNestedNameSpecifier().isDependent()) {
+ if (QualifierLoc) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
DC = SemaRef.computeDeclContext(SS);
if (DC && SemaRef.RequireCompleteDeclContext(SS, DC))
return nullptr;
- } else if (!QualifierLoc) {
+ } else {
DC = SemaRef.FindInstantiatedContext(D->getLocation(),
D->getDeclContext(),
TemplateArgs);
@@ -3613,22 +3423,12 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
return nullptr;
}
- if (QualifierLoc && QualifierLoc.getNestedNameSpecifier().isDependent()) {
- if (SemaRef.CheckDependentFunctionTemplateSpecialization(
- Method,
- DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
- Previous))
- Method->setInvalidDecl();
- } else {
- if (Previous.empty())
- SemaRef.LookupQualifiedName(Previous, DC);
- if (SemaRef.CheckFunctionTemplateSpecialization(
- Method,
- DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
- Previous))
- Method->setInvalidDecl();
- IsExplicitSpecialization = true;
- }
+ if (SemaRef.CheckFunctionTemplateSpecialization(
+ Method, DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
+ Previous))
+ Method->setInvalidDecl();
+
+ IsExplicitSpecialization = true;
} else if (const ASTTemplateArgumentListInfo *ArgsWritten =
D->getTemplateSpecializationArgsAsWritten()) {
SemaRef.LookupQualifiedName(Previous, DC);
@@ -4972,48 +4772,14 @@ Decl *TemplateDeclInstantiator::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D)
}
Decl *TemplateDeclInstantiator::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
- ArrayRef<TemplateParameterList *> FriendTPLs = D->getTemplateParameterLists();
+ // FIXME: We need to be able to instantiate FriendTemplateDecls.
+ unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "cannot instantiate %0 yet");
+ SemaRef.Diag(D->getLocation(), DiagID)
+ << D->getDeclKindName();
- TypeSourceInfo *FriendTSI = D->getFriendType();
- if (FriendTSI && D->isPackExpansion() && InstantiateFriendPackExpansion(D))
- return nullptr;
-
- LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
- SmallVector<TemplateParameterList *, 1> InstTPLs;
- if (SubstTemplateParameterLists(FriendTPLs, InstTPLs))
- return nullptr;
-
- FriendDecl::FriendUnion ToFriend;
- TemplateName ToTemplate;
- if (FriendTSI) {
- std::optional<SubstitutedFriend> Substituted = SubstFriendTemplateType(
- SemaRef, FriendTSI, D->getFriendTemplateName(), TemplateArgs,
- D->getLocation(), DeclarationName());
- if (!Substituted || Substituted->empty())
- return nullptr;
- ToFriend = Substituted->TypeInfo;
- ToTemplate = Substituted->TemplateName;
- } else if (!D->getFriendTemplateName().isNull()) {
- if (auto *InstTemplate =
- cast_or_null<TemplateDecl>(Visit(D->getFriendDecl())))
- ToTemplate = TemplateName(InstTemplate);
- else
- return nullptr;
- } else {
- if (auto *InstFriendDecl =
- cast_or_null<NamedDecl>(Visit(D->getFriendDecl())))
- ToFriend = InstFriendDecl;
- else
- return nullptr;
- }
-
- FriendTemplateDecl *InstFriend = FriendTemplateDecl::Create(
- SemaRef.Context, Owner, D->getLocation(), ToFriend, D->getFriendLoc(),
- InstTPLs, /*EllipsisLoc=*/{}, ToTemplate);
-
- InstFriend->setAccess(AS_public);
- Owner->addDecl(InstFriend);
- return InstFriend;
+ return nullptr;
}
Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) {
@@ -5158,33 +4924,6 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
return InstL;
}
-bool TemplateDeclInstantiator::SubstTemplateParameterLists(
- ArrayRef<TemplateParameterList *> TPLs,
- SmallVectorImpl<TemplateParameterList *> &InstTPLs) {
- llvm::SaveAndRestore RAII(EvaluateConstraints, false);
- for (TemplateParameterList *L : TPLs) {
- TemplateParameterList *InstParams = SubstTemplateParams(L);
- if (!InstParams)
- return true;
-
- if (Expr *RequiresClause = L->getRequiresClause()) {
- ExprResult InstRequiresClause =
- SemaRef.SubstConstraintExprWithoutSatisfaction(RequiresClause,
- TemplateArgs);
- if (!InstRequiresClause.isUsable())
- return true;
-
- InstParams = TemplateParameterList::Create(
- SemaRef.Context, InstParams->getTemplateLoc(),
- InstParams->getLAngleLoc(), InstParams->asArray(),
- InstParams->getRAngleLoc(), InstRequiresClause.get());
- }
-
- InstTPLs.push_back(InstParams);
- }
- return false;
-}
-
TemplateParameterList *
Sema::SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -5427,8 +5166,9 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
return InstPartialSpec;
}
-TypeSourceInfo *TemplateDeclInstantiator::SubstFunctionType(
- FunctionDecl *D, SmallVectorImpl<ParmVarDecl *> &Params) {
+TypeSourceInfo*
+TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
+ SmallVectorImpl<ParmVarDecl *> &Params) {
TypeSourceInfo *OldTInfo = D->getTypeSourceInfo();
assert(OldTInfo && "substituting function without type source info");
assert(Params.empty() && "parameter vector is non-empty at start");
@@ -5497,10 +5237,8 @@ TypeSourceInfo *TemplateDeclInstantiator::SubstFunctionType(
continue;
}
- ParmVarDecl *Parm = SemaRef.SubstParmVarDecl(
- OldParam, TemplateArgs, /*indexAdjustment=*/0,
- /*NumExpansions=*/std::nullopt,
- /*ExpectParameterPack=*/false, EvaluateConstraints);
+ ParmVarDecl *Parm =
+ cast_or_null<ParmVarDecl>(VisitParmVarDecl(OldParam));
if (!Parm)
return nullptr;
Params.push_back(Parm);
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index e973b7ae71954..bec62e7c55606 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2408,37 +2408,26 @@ void ASTDeclReader::VisitFriendDecl(FriendDecl *D) {
D->Friend = readDeclAs<NamedDecl>();
else
D->Friend = readTypeSourceInfo();
+ for (unsigned i = 0; i != D->NumTPLists; ++i)
+ D->getTrailingObjects()[i] = Record.readTemplateParameterList();
D->NextFriend = readDeclID().getRawValue();
+ D->UnsupportedFriend = (Record.readInt() != 0);
D->FriendLoc = readSourceLocation();
D->EllipsisLoc = readSourceLocation();
}
void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
VisitDecl(D);
- for (unsigned I = 0; I != D->NumTPLists; ++I)
- D->getTrailingObjects()[I] = Record.readTemplateParameterList();
- auto Kind = static_cast<FriendTemplateDeclKind>(Record.readInt());
- switch (Kind) {
- case FTDK_Type:
- D->Friend = readTypeSourceInfo();
- break;
- case FTDK_Decl:
+ unsigned NumParams = Record.readInt();
+ D->NumParams = NumParams;
+ D->Params = new (Reader.getContext()) TemplateParameterList *[NumParams];
+ for (unsigned i = 0; i != NumParams; ++i)
+ D->Params[i] = Record.readTemplateParameterList();
+ if (Record.readInt()) // HasFriendDecl
D->Friend = readDeclAs<NamedDecl>();
- break;
- case FTDK_Template:
- D->Template = Record.readTemplateName();
- assert(D->Template.getAsTemplateDecl() &&
- "friend template name must resolve to a template declaration");
- D->Friend = D->Template.getAsTemplateDecl();
- break;
- case FTDK_Dependent:
+ else
D->Friend = readTypeSourceInfo();
- D->Template = Record.readTemplateName();
- break;
- }
- D->NextFriend = readDeclID().getRawValue();
D->FriendLoc = readSourceLocation();
- D->EllipsisLoc = readSourceLocation();
}
void ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
@@ -4115,11 +4104,10 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) {
D = AccessSpecDecl::CreateDeserialized(Context, ID);
break;
case DECL_FRIEND:
- D = FriendDecl::CreateDeserialized(Context, ID);
+ D = FriendDecl::CreateDeserialized(Context, ID, Record.readInt());
break;
case DECL_FRIEND_TEMPLATE:
- D = FriendTemplateDecl::CreateDeserialized(Context, ID,
- /*NumTPLists=*/Record.readInt());
+ D = FriendTemplateDecl::CreateDeserialized(Context, ID);
break;
case DECL_CLASS_TEMPLATE:
D = ClassTemplateDecl::CreateDeserialized(Context, ID);
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 6f67acf9a6e7e..d8f5ed9afdde1 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1831,6 +1831,9 @@ void ASTDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) {
}
void ASTDeclWriter::VisitFriendDecl(FriendDecl *D) {
+ // Record the number of friend type template parameter lists here
+ // so as to simplify memory allocation during deserialization.
+ Record.push_back(D->NumTPLists);
VisitDecl(D);
bool hasFriendDecl = isa<NamedDecl *>(D->Friend);
Record.push_back(hasFriendDecl);
@@ -1838,47 +1841,26 @@ void ASTDeclWriter::VisitFriendDecl(FriendDecl *D) {
Record.AddDeclRef(D->getFriendDecl());
else
Record.AddTypeSourceInfo(D->getFriendType());
+ for (unsigned i = 0; i < D->NumTPLists; ++i)
+ Record.AddTemplateParameterList(D->getFriendTypeTemplateParameterList(i));
Record.AddDeclRef(D->getNextFriend());
+ Record.push_back(D->UnsupportedFriend);
Record.AddSourceLocation(D->FriendLoc);
Record.AddSourceLocation(D->EllipsisLoc);
Code = serialization::DECL_FRIEND;
}
void ASTDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
- // Record the number of template parameter lists here to simplify memory
- // allocation during deserialization.
- Record.push_back(D->NumTPLists);
VisitDecl(D);
- for (TemplateParameterList *TPL : D->getTemplateParameterLists())
- Record.AddTemplateParameterList(TPL);
- FriendTemplateDeclKind Kind;
- if (D->getFriendType()) {
- Kind = D->Template.isNull() ? FTDK_Type : FTDK_Dependent;
- } else if (D->Template.isNull()) {
- assert(D->getFriendDecl());
- Kind = FTDK_Decl;
- } else {
- Kind = FTDK_Template;
- }
- Record.push_back(Kind);
- switch (Kind) {
- case FTDK_Type:
- Record.AddTypeSourceInfo(D->getFriendType());
- break;
- case FTDK_Dependent:
- Record.AddTypeSourceInfo(D->getFriendType());
- Record.AddTemplateName(D->Template);
- break;
- case FTDK_Decl:
+ Record.push_back(D->getNumTemplateParameters());
+ for (unsigned i = 0, e = D->getNumTemplateParameters(); i != e; ++i)
+ Record.AddTemplateParameterList(D->getTemplateParameterList(i));
+ Record.push_back(D->getFriendDecl() != nullptr);
+ if (D->getFriendDecl())
Record.AddDeclRef(D->getFriendDecl());
- break;
- case FTDK_Template:
- Record.AddTemplateName(D->Template);
- break;
- }
- Record.AddDeclRef(D->getNextFriend());
- Record.AddSourceLocation(D->FriendLoc);
- Record.AddSourceLocation(D->EllipsisLoc);
+ else
+ Record.AddTypeSourceInfo(D->getFriendType());
+ Record.AddSourceLocation(D->getFriendLoc());
Code = serialization::DECL_FRIEND_TEMPLATE;
}
diff --git a/clang/test/AST/friend-template-decl.cpp b/clang/test/AST/friend-template-decl.cpp
deleted file mode 100644
index c9816771991b9..0000000000000
--- a/clang/test/AST/friend-template-decl.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -ast-print %s | FileCheck %s --check-prefix=PRINT
-// RUN: %clang_cc1 -std=c++20 -ast-dump -ast-dump-filter C %s | FileCheck %s --check-prefix=DUMP
-// RUN: %clang_cc1 -std=c++20 -ast-dump=json -ast-dump-filter C %s | FileCheck %s --check-prefix=JSON
-// RUN: %clang_cc1 -std=c++20 -x c++-header -emit-pch -o %t %s
-// RUN: %clang_cc1 -std=c++20 -x c++ -include-pch %t -ast-dump-all -ast-dump-filter C /dev/null | FileCheck %s --check-prefix=DUMP
-
-namespace N {
-template <class T> struct A {
- template <class U> struct B;
-};
-
-template <class V> struct C {
- template <class T> template <class U> friend struct A<T>::B;
-};
-
-template struct C<int>;
-}
-
-// PRINT: template<> struct C<int> {
-// PRINT-NEXT: template <class T> template <class U> friend struct A<T>::B;
-
-// DUMP: ClassTemplateDecl {{.*}} C
-// DUMP: FriendTemplateDecl {{.*}} 'struct A<T>::B'
-// DUMP-NEXT: |-TemplateTypeParmDecl {{.*}} T
-// DUMP-NEXT: `-TemplateTypeParmDecl {{.*}} U
-// DUMP: ClassTemplateSpecializationDecl {{.*}} struct C definition
-// DUMP-NOT: <<<NULL>>>
-// DUMP: FriendTemplateDecl {{.*}} qualified
-// DUMP-NEXT: |-NestedNameSpecifier TypeSpec 'A<T>'
-// DUMP-NEXT: |-ClassTemplateDecl
-// DUMP-NEXT: |-TemplateTypeParmDecl {{.*}} T
-// DUMP-NEXT: `-TemplateTypeParmDecl {{.*}} U
-
-// JSON: "kind": "ClassTemplateSpecializationDecl",
-// JSON: "kind": "FriendTemplateDecl",
-// JSON-NEXT: "loc": {
-// JSON: "templateName": "A<T>::B"
diff --git a/clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp b/clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp
index 6c55e81c58c18..f7216ea7eb7b0 100644
--- a/clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp
+++ b/clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp
@@ -36,7 +36,7 @@ class A {
public:
class foo {};
static int y;
- template <typename S> friend class B<S>::ty;
+ template <typename S> friend class B<S>::ty; // expected-warning {{dependent nested name specifier 'B<S>' for friend class declaration is not supported}}
};
template<typename T> class B { typedef int ty; };
@@ -74,7 +74,7 @@ struct {
friend
float;
- template<typename T> friend class A<T>::foo;
+ template<typename T> friend class A<T>::foo; // expected-warning {{not supported}}
} a;
void testA() { (void)sizeof(A<int>); }
diff --git a/clang/test/CXX/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp
index 32ff4d72d30f3..646b82eb40fd7 100644
--- a/clang/test/CXX/drs/cwg18xx.cpp
+++ b/clang/test/CXX/drs/cwg18xx.cpp
@@ -375,7 +375,7 @@ namespace cwg1837 { // cwg1837: 3.3
#endif
} // namespace cwg1837
-namespace cwg1862 { // cwg1862: 24
+namespace cwg1862 { // cwg1862: no
template<class T>
struct A {
struct B {
@@ -416,24 +416,29 @@ struct A<float*> {
};
class C {
- int private_int; // #cwg1862-C-private_int
+ int private_int;
template<class T>
friend struct A<T>::B;
+ // expected-warning at -1 {{dependent nested name specifier 'A<T>' for friend class declaration is not supported; turning off access control for 'C'}}
template<class T>
friend void A<T>::f();
+ // expected-warning at -1 {{dependent nested name specifier 'A<T>' for friend class declaration is not supported; turning off access control for 'C'}}
+ // FIXME: this is ill-formed, because A<T>::D does not end with a simple-template-id
template<class T>
friend void A<T>::D::g();
- // expected-error at -1 {{'A<T>::D' does not name a class template}}
+ // expected-warning at -1 {{dependent nested name specifier 'A<T>::D' for friend class declaration is not supported; turning off access control for 'C'}}
template<class T>
friend int *A<T*>::h();
+ // expected-warning at -1 {{dependent nested name specifier 'A<T *>' for friend class declaration is not supported; turning off access control for 'C'}}
template<class T>
template<T U>
friend T A<T>::i();
+ // expected-warning at -1 {{dependent nested name specifier 'A<T>' for friend class declaration is not supported; turning off access control for 'C'}}
};
C c;
@@ -445,16 +450,11 @@ void A<int>::B::e() { (void)c.private_int; }
template<class T>
void A<T>::f() { (void)c.private_int; }
int A<int>::f() { (void)c.private_int; return 0; }
-// expected-error at -1 {{'private_int' is a private member of 'cwg1862::C'}}
-// expected-note@#cwg1862-C-private_int {{implicitly declared private here}}
+// FIXME: both definition of 'D::g' are not friends, so they don't have access to 'private_int'
template<class T>
void A<T>::D::g() { (void)c.private_int; }
-// expected-error at -1 {{'private_int' is a private member of 'cwg1862::C'}}
-// expected-note@#cwg1862-C-private_int {{implicitly declared private here}}
void A<int>::D::g() { (void)c.private_int; }
-// expected-error at -1 {{'private_int' is a private member of 'cwg1862::C'}}
-// expected-note@#cwg1862-C-private_int {{implicitly declared private here}}
template<class T>
T A<T>::h() { (void)c.private_int; }
diff --git a/clang/test/CXX/drs/cwg19xx.cpp b/clang/test/CXX/drs/cwg19xx.cpp
index 53ff58c7cbffd..8162f9caa8f15 100644
--- a/clang/test/CXX/drs/cwg19xx.cpp
+++ b/clang/test/CXX/drs/cwg19xx.cpp
@@ -94,26 +94,26 @@ namespace cwg1909 { // cwg1909: 3.7
};
} // namespace cwg1909
-namespace cwg1918 { // cwg1918: 24
+namespace cwg1918 { // cwg1918: no
template<typename T> struct A {
class B {
class C {};
};
};
class X {
- static int x; // #cwg1918-X-x
+ static int x;
+ // FIXME: this is ill-formed, because A<T>::B::C does not end with a simple-template-id
template <typename T>
friend class A<T>::B::C;
- // expected-error at -1 {{'A<T>::B' does not name a class template}}
+ // expected-warning at -1 {{dependent nested name specifier 'A<T>::B' for friend class declaration is not supported; turning off access control for 'X'}}
};
template<> struct A<int> {
typedef struct Q B;
};
struct Q {
class C {
+ // FIXME: 'f' is not a friend, so 'X::x' is not accessible
int f() { return X::x; }
- // expected-error at -1 {{'x' is a private member of 'cwg1918::X'}}
- // expected-note@#cwg1918-X-x {{implicitly declared private here}}
};
};
} // namespace cwg1918
@@ -159,7 +159,7 @@ derived d2(42, 9);
#endif
} // namespace cwg1941
-namespace cwg1945 { // cwg1945: 24
+namespace cwg1945 { // cwg1945: no
template<typename T> struct A {
class B {
class C {};
@@ -167,9 +167,10 @@ template<typename T> struct A {
};
class X {
static int x;
+ // FIXME: this is ill-formed, because A<T>::B::C does not end with a simple-template-id
template <typename T>
friend class A<T>::B::C;
- // expected-error at -1 {{'A<T>::B' does not name a class template}}
+ // expected-warning at -1 {{dependent nested name specifier 'A<T>::B' for friend class declaration is not supported; turning off access control for 'X'}}
};
} // namespace cwg1945
diff --git a/clang/test/CXX/drs/cwg28xx.cpp b/clang/test/CXX/drs/cwg28xx.cpp
index 7352da80e7b41..02c8f30249683 100644
--- a/clang/test/CXX/drs/cwg28xx.cpp
+++ b/clang/test/CXX/drs/cwg28xx.cpp
@@ -178,21 +178,17 @@ namespace cwg2858 { // cwg2858: 19
template<typename... Ts>
struct A {
+ // FIXME: The nested-name-specifier in the following friend declarations are declarative,
+ // but we don't treat them as such (yet).
friend void Ts...[0]::f();
- // since-cxx26-error at -1 {{a pack indexing specifier cannot be used in a nested name specifier of a friend declaration}}
template<typename U>
friend void Ts...[0]::g();
- // since-cxx26-error at -1 {{a pack indexing specifier cannot be used in a nested name specifier of a friend declaration}}
friend struct Ts...[0]::B;
- // since-cxx26-error at -1 {{a pack indexing specifier cannot be used in a nested name specifier of a friend declaration}}
+ // FIXME: The index of the pack-index-specifier is printed as a memory address in the diagnostic.
template<typename U>
friend struct Ts...[0]::C;
- // since-cxx26-error at -1 {{a pack indexing specifier cannot be used in a nested name specifier of a friend declaration}}
-
- template<typename U>
- friend struct Ts...[0]::template B<U>::C;
- // since-cxx26-error at -1 {{a pack indexing specifier cannot be used in a nested name specifier of a friend declaration}}
+ // since-cxx26-warning at -1 {{dependent nested name specifier 'Ts...[0]' for friend template declaration is not supported; ignoring this friend declaration}}
};
#endif
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index eb1898b56762d..451554a36d70d 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -396,7 +396,7 @@ namespace cwg637 { // cwg637: 3.0
}
} // namespace cwg637
-namespace cwg638 { // cwg638: 24
+namespace cwg638 { // cwg638: no
template<typename T> struct A {
struct B;
void f();
@@ -407,29 +407,26 @@ namespace cwg638 { // cwg638: 24
};
class X {
- typedef int type; // #cwg638-X-type
+ typedef int type;
template<class T> friend struct A<T>::B;
+ // expected-warning at -1 {{dependent nested name specifier 'A<T>' for friend class declaration is not supported; turning off access control for 'X'}}
template<class T> friend void A<T>::f();
+ // expected-warning at -1 {{dependent nested name specifier 'A<T>' for friend class declaration is not supported; turning off access control for 'X'}}
template<class T> friend void A<T>::g();
+ // expected-warning at -1 {{dependent nested name specifier 'A<T>' for friend class declaration is not supported; turning off access control for 'X'}}
template<class T> friend void A<T>::C::h();
- // expected-error at -1 {{'A<T>::C' does not name a class template}}
+ // expected-warning at -1 {{dependent nested name specifier 'A<T>::C' for friend class declaration is not supported; turning off access control for 'X'}}
};
template<> struct A<int> {
- X::type a;
- // expected-error at -1 {{'type' is a private member of 'cwg638::X'}}
- // expected-note@#cwg638-X-type {{implicitly declared private here}}
+ X::type a; // FIXME: private
struct B {
X::type b; // ok
};
- int f() { X::type c; }
- // expected-error at -1 {{'type' is a private member of 'cwg638::X'}}
- // expected-note@#cwg638-X-type {{implicitly declared private here}}
+ int f() { X::type c; } // FIXME: private
void g() { X::type d; } // ok
struct D {
- void h() { X::type e; }
- // expected-error at -1 {{'type' is a private member of 'cwg638::X'}}
- // expected-note@#cwg638-X-type {{implicitly declared private here}}
+ void h() { X::type e; } // FIXME: private
};
};
} // namespace cwg638
diff --git a/clang/test/CXX/temp/temp.decls/temp.friend/p1.cpp b/clang/test/CXX/temp/temp.decls/temp.friend/p1.cpp
index 3ebd32f713371..b8092afaffef3 100644
--- a/clang/test/CXX/temp/temp.decls/temp.friend/p1.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.friend/p1.cpp
@@ -387,29 +387,3 @@ template <class T> class A {
friend void foo<T>() {} // expected-error {{ambiguous}} expected-error{{no candidate function template was found for dependent friend function template specialization}}
};
}
-
-namespace test19 {
-template <class V> class B;
-
-template <class T> struct A {
- template <class U> static void f(B<T> &);
-};
-
-template <class V> class B {
- int n; // #test19-B-n
- friend void A<V>::template f<int>(B<V> &);
-};
-
-template <class T>
-template <class U>
-void A<T>::f(B<T> &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test19::B<long>'}}
- // expected-note@#test19-B-n {{implicitly declared private here}}
-}
-
-template class B<long>;
-template void A<long>::f<int>(B<long> &);
-template void A<long>::f<double>(B<long> &);
-// expected-note at -1 {{in instantiation of function template specialization 'test19::A<long>::f<double>' requested here}}
-}
diff --git a/clang/test/CXX/temp/temp.decls/temp.friend/p5.cpp b/clang/test/CXX/temp/temp.decls/temp.friend/p5.cpp
index cb0b046eb4132..a292d0de97a39 100644
--- a/clang/test/CXX/temp/temp.decls/temp.friend/p5.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.friend/p5.cpp
@@ -1,8 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c++14 -fcxx-exceptions -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c++2c -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
namespace test0 {
template <class T> class A {
@@ -10,7 +6,7 @@ namespace test0 {
};
class B {
- template <class T> friend class A<T>::Member;
+ template <class T> friend class A<T>::Member; // expected-warning {{not supported}}
int n;
};
@@ -23,7 +19,7 @@ namespace test1 {
class C {
static void foo();
- template <class T> friend void A<T>::f();
+ template <class T> friend void A<T>::f(); // expected-warning {{not supported}}
};
template <class T> struct A {
@@ -39,30 +35,25 @@ namespace test1 {
};
}
+// FIXME: these should fail!
namespace test2 {
template <class T> struct A;
class C {
- static void foo(); // #test2-C-foo
- template <class T> friend void A<T>::g();
+ static void foo();
+ template <class T> friend void A<T>::g(); // expected-warning {{not supported}}
};
template <class T> struct A {
void f() { C::foo(); }
- // expected-error at -1 {{'foo' is a private member of 'test2::C'}}
- // expected-note@#test2-C-foo {{implicitly declared private here}}
};
template <class T> struct A<T*> {
void f() { C::foo(); }
- // expected-error at -1 {{'foo' is a private member of 'test2::C'}}
- // expected-note@#test2-C-foo {{implicitly declared private here}}
};
template <> struct A<char> {
void f() { C::foo(); }
- // expected-error at -1 {{'foo' is a private member of 'test2::C'}}
- // expected-note@#test2-C-foo {{implicitly declared private here}}
};
}
@@ -75,7 +66,7 @@ namespace test3 {
template <class U> class C {
int i;
- template <class T> friend struct A<T>::Inner;
+ template <class T> friend struct A<T>::Inner; // expected-warning {{not supported}}
};
template <class T> int A<T>::Inner::foo() {
@@ -88,1091 +79,24 @@ namespace test3 {
}
namespace test4 {
- template <class T> struct A {
+ template <class T> struct X {
template <class U> void operator+=(U);
-
+
template <class V>
template <class U>
- friend void A<V>::operator+=(U);
+ friend void X<V>::operator+=(U); // expected-warning {{not supported}}
};
- void test() {
- A<int>() += 1.0;
+ void test() {
+ X<int>() += 1.0;
}
}
namespace test5 {
template<template <class> class T> struct A {
- template<template <class> class U> friend void A<U>::foo();
+ template<template <class> class U> friend void A<U>::foo(); // expected-warning {{not supported}}
};
template <class> struct B {};
template class A<B>;
}
-
-namespace test6 {
- template <class T> struct A {
- struct B {
- static int f();
- };
- };
-
- struct C {
- int n;
- template <class T> friend struct A<T>::B;
- };
-
- template <class T> int A<T>::B::f() {
- C c;
- c.n = 0;
- return 0;
- }
-
- int k = A<int>::B::f();
-}
-
-namespace test7 {
- template <class T> struct A {
- struct D {
- void g();
- };
- };
-
- struct C {
- template <class T> friend void A<T>::D::g();
- // expected-error at -1 {{'A<T>::D' does not name a class template}}
- };
-}
-
-namespace test8 {
- template <class T> struct A { // #test8-A
- T h();
- };
-
- template <> struct A<int> {
- int h();
- };
-
- template <> struct A<float *> {
- int *h();
- };
-
- class C {
- int n; // #test8-C-n
- template <class T> friend int *A<T *>::h();
- };
-
- template <class T> T A<T>::h() {
- return T();
- }
-
- int A<int>::h() {
- C c;
- c.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test8::C'}}
- // expected-note@#test8-C-n {{implicitly declared private here}}
- // expected-note@#test8-A {{candidate friend template ignored: could not match 'T *' against 'int'}}
- return 0;
- }
-
- template <> int *A<int *>::h() {
- C c;
- c.n = 0;
- return nullptr;
- }
-
- int *A<float *>::h() {
- C c;
- c.n = 0;
- return nullptr;
- }
-
- int *t1 = A<int *>().h();
- int *t2 = A<float *>().h();
- int t3 = A<int>().h();
-}
-
-namespace test9 {
- template <class T> struct A {
- template <T U> T i();
- };
-
- template <> struct A<int> {
- template <int U> int i();
- };
-
- struct C {
- int n;
- template <class T> template <T U> friend T A<T>::i();
- };
-
- template <class T> template <T U> T A<T>::i() {
- C c;
- c.n = 0;
- return U;
- }
-
- template <int U> int A<int>::i() {
- C c;
- c.n = 0;
- return U;
- }
-
- int x = A<int>().i<1>();
-}
-
-namespace test10 {
- template <class T> struct A;
- class C {
- static void foo(); // #test10-C-foo
- template <class T> friend void A<T>::f();
- };
-
- template <class T> struct A {
- void f() { C::foo(); }
- };
-
- template <> struct A<int> {
- int f() {
- C::foo();
- // expected-error at -1 {{'foo' is a private member of 'test10::C'}}
- // expected-note@#test10-C-foo {{implicitly declared private here}}
- return 0;
- }
- };
-}
-
-namespace test11 {
- template <class> struct C;
- template <class T> struct A {
- template <class> struct B;
- };
- template <class T> struct D : A<T> {
- using A<T>::B;
- };
-
- template <class T> struct C {
- int n;
- template <class U> friend struct D<T>::B;
- };
-
- template <> template <class U> struct A<int>::B {
- static int f(C<int> &c) {
- c.n = 0;
- return 0;
- }
- };
-
- int x = A<int>::B<void>::f(*new C<int>);
-}
-
-namespace test12 {
- template <class T> struct A {
- template <T> struct B {
- static int f();
- };
- };
-
- template <class T> struct C {
- int n;
- template <class U> template <U V> friend struct A<U>::B;
- };
-
- template <class T> template <T V> int A<T>::B<V>::f() {
- C<T> c;
- c.n = 0;
- return 0;
- }
-
- int x = A<int>::B<0>::f();
-}
-
-namespace test13 {
- template <typename T> struct S {
- template <typename> friend class T::template A<int>::B;
- };
-}
-
-namespace test14 {
- template <class T> struct A {
- template <bool V> struct B {
- static int f(B<false> &x) { return x.n; }
-
- private:
- int n;
- template <bool> friend struct A<T>::B;
- };
- };
-
- int x = A<int>::B<true>::f(*new A<int>::B<false>);
-}
-
-namespace test15 {
- template <class T> struct A {
- T f();
- };
-
- template <> struct A<int> {
- void f();
- };
-
- class C {
- int n; // #test15-C-n
- template <class T> friend T A<T>::f();
- };
-
- void A<int>::f() {
- C c;
- c.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test15::C'}}
- // expected-note@#test15-C-n {{implicitly declared private here}}
- }
-}
-
-namespace test16 {
- template <class T> struct A {
- template <T U> T i();
- };
-
- template <> struct A<int> {
- template <int U> void i();
- };
-
- class C {
- int n; // #test16-C-n
- template <class T> template <T U> friend T A<T>::i();
- };
-
- template <int U> void A<int>::i() {
- C c;
- c.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test16::C'}}
- // expected-note@#test16-C-n {{implicitly declared private here}}
- }
-}
-
-namespace test17 {
- template <class T> class A;
-
- template <class T>
- struct B {
- template <bool V>
- struct C {
- int f(A<T> *p) { return p->x; }
- };
- };
-
- template <class T>
- class A {
- friend struct B<T>::template C<true>;
- int x;
- };
-
- template struct B<int>::C<true>;
-}
-
-namespace test18 {
- template <class T> class A;
-
- template <class T>
- struct B {
- template <bool V>
- struct C {
- int f(A<T> *p) { return p->x; }
- // expected-error at -1 {{'x' is a private member of 'test18::A<int>'}}
- };
- };
-
- template <class T>
- class A {
- friend struct B<T>::template C<false>;
- int x;
- // expected-note at -1 {{implicitly declared private here}}
- };
-
- template struct B<int>::C<true>;
- // expected-note at -1 {{in instantiation of member function 'test18::B<int>::C<true>::f' requested here}}
-}
-
-namespace test19 {
- template <class...> struct A {
- struct B;
- static void f();
- };
-
- struct C {
- template <class T, class U> // #test19-U-type
- friend struct A<T>::B;
- // expected-error at -1 {{template parameter of friend declaration cannot be deduced from 'A<T>'}}
- // expected-note@#test19-U-type {{non-deducible template parameter 'U'}}
-
- template <class T, class U> // #test19-U-function
- friend void A<T>::f();
- // expected-error at -1 {{template parameter of friend declaration cannot be deduced from 'A<T>'}}
- // expected-note@#test19-U-function {{non-deducible template parameter 'U'}}
-
- template <class... Ts> // #test19-Ts
- friend struct A<Ts..., int>::B;
- // expected-error at -1 {{template parameter of friend declaration cannot be deduced from 'A<Ts..., int>'}}
- // expected-note@#test19-Ts {{non-deducible template parameter 'Ts'}}
- };
-}
-
-namespace test20 {
- class D;
-
- template <class T> struct A {
- template <class, class U> struct B {
- struct C {
- static void f(D &);
- };
- static void g(D &);
- };
- };
-
- class D {
- int n;
-
- template <class T>
- template <class U>
- friend struct A<T>::B<T, U>::C;
-
- template <class T>
- template <class U>
- friend void A<T>::B<T, U>::g(D &);
- };
-
- template <class T>
- template <class V, class U>
- void A<T>::B<V, U>::C::f(D &x) {
- x.n = 0;
- }
-
- template <class T>
- template <class V, class U>
- void A<T>::B<V, U>::g(D &x) {
- x.n = 0;
- }
-
- template struct A<int>::B<int, double>;
-}
-
-namespace test21 {
- class C;
-
- template <class T> struct A {
- template <class U> struct B;
- };
-
- class C {
- int n; // #test21-C-n
- template <class T>
- template <class U>
- friend struct A<T>::B;
- };
-
- template <> struct A<int> {
- template <int U> struct B {
- static void f(C &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test21::C'}}
- // expected-note@#test21-C-n {{implicitly declared private here}}
- }
- };
- };
-
- template struct A<int>::B<0>;
-}
-
-namespace test22 {
- class C;
-
- template <class T> struct A {
- struct B;
- };
-
- class C {
- int n; // #test22-C-n
- template <class T> friend struct A<T>::B;
- };
-
- template <> struct A<int> {
- union B {
- static void f(C &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test22::C'}}
- // expected-note@#test22-C-n {{implicitly declared private here}}
- }
- };
- };
-}
-
-namespace test23 {
- class B;
-
- template <class T> struct A {
- template <class U> static void f(B &);
- };
-
- class B {
- int n; // #test23-B-n
- template <class T>
- template <class U>
- friend void A<T>::f(B &);
- };
-
- template <> struct A<int> {
- template <int U> static void f(B &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test23::B'}}
- // expected-note@#test23-B-n {{implicitly declared private here}}
- }
- };
-
- template void A<int>::f<0>(B &);
-}
-
-namespace test24 {
- class B;
-
- template <class T> struct A {
- static void f(B &);
- };
-
- class B {
- int n; // #test24-B-n
- template <class T> friend void A<T>::f(B &);
- };
-
- template <> struct A<int> {
- static void f(B &x, ...) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test24::B'}}
- // expected-note@#test24-B-n {{implicitly declared private here}}
- }
- };
-}
-
-namespace test25 {
- class C;
-
- template <class... Ts> struct A {
- struct B {
- static void f(C &);
- };
- };
-
- class C {
- int n;
- template <class... Ts> friend struct A<Ts...>::B;
- };
-
- template <class... Ts> void A<Ts...>::B::f(C &x) {
- x.n = 0;
- }
-
- template void A<int, double>::B::f(C &);
-}
-
-namespace test26 {
- class B;
-
- template <class T> struct A {
- template <class U> static void f(U);
- };
-
- template <> struct A<int> {
- template <class U> static void f(U);
- };
-
- class B {
- int n;
- template <class T>
- template <class U>
- friend void A<T>::f(U);
- };
-
- template <class T>
- template <class U>
- void A<T>::f(U) {
- B b;
- b.n = 0;
- }
-
- template <class U>
- void A<int>::f(U) {
- B b;
- b.n = 0;
- }
-
- template void A<long>::f<double>(double);
- template void A<int>::f<double>(double);
-}
-
-namespace test27 {
- template <class T> struct A {
- struct B {
- template <class U> static void g(U);
- template <class U> struct C;
- };
- };
-
- template <class V> struct D {
- template <class U> friend void A<V>::B::g(U);
- // expected-error at -1 {{'A<V>::B' does not name a class template}}
-
- template <class U> friend class A<V>::B::C;
- // expected-error at -1 {{'A<V>::B' does not name a class template}}
- };
-}
-
-namespace test28 {
- class B;
-
- template <class T> struct A {
- ~A();
- };
-
- template <> struct A<int> {
- ~A();
- };
-
- class B {
- int n;
- template <class T> friend A<T>::~A();
- };
-
- template <class T> A<T>::~A() {
- B b;
- b.n = 0;
- }
-
- A<int>::~A() {
- B b;
- b.n = 0;
- }
-
- template struct A<long>;
-}
-
-namespace test29 {
- template <class T> class D;
-
- template <class T> struct A {
- template <class I> struct B {
- template <class U> struct C {
- static void h(D<T> &);
- };
- };
- };
-
- template <class V> class D {
- int n;
-
- template <class U>
- friend class A<V>::B<int>::C;
- };
-
- template <class T>
- template <class I>
- template <class U>
- void A<T>::B<I>::C<U>::h(D<T> &x) {
- x.n = 0;
- }
-
- template struct A<int>::B<int>::C<double>;
-}
-
-namespace test30 {
- class B;
-
- template <class T> struct A {
- template <class U> static void f(U);
- };
-
- template <> struct A<int> {
- template <class U> static void f(U *);
- };
-
- class B {
- int n; // #test30-B-n
- template <class T>
- template <class U>
- friend void A<T>::f(U);
- };
-
- template <class U>
- void A<int>::f(U *) {
- B b;
- b.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test30::B'}}
- // expected-note@#test30-B-n {{implicitly declared private here}}
- }
-
- template void A<int>::f<double>(double *);
-}
-
-namespace test31 {
- class B;
-
- template <class T> struct A {
- static void f(B &) noexcept;
- };
-
- template <> struct A<int> {
- static void f(B &);
- };
-
- class B {
- int n; // #test31-B-n
- template <class T> friend void A<T>::f(B &) noexcept;
- };
-
- template <class T> void A<T>::f(B &x) noexcept {
- x.n = 0;
- }
-
- void A<int>::f(B &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test31::B'}}
- // expected-note@#test31-B-n {{implicitly declared private here}}
- }
-
- template void A<long>::f(B &) noexcept;
-}
-
-namespace test32 {
- class B;
-
- template <class T> struct A {
- A();
- operator int();
- };
-
- template <> struct A<char> {
- A();
- operator int();
- };
-
- class B {
- int n;
- template <class T> friend A<T>::A();
- template <class T> friend A<T>::operator int();
- };
-
- template <class T> A<T>::A() {
- B b;
- b.n = 0;
- }
-
- template <class T> A<T>::operator int() {
- B b;
- b.n = 0;
- return 0;
- }
-
- A<char>::A() {
- B b;
- b.n = 0;
- }
-
- A<char>::operator int() {
- B b;
- b.n = 0;
- return 0;
- }
-
- template struct A<long>;
-}
-
-namespace test33 {
- struct A {
- template <class> struct D {
- struct M;
- template <class> struct N;
- static void f();
- template <class> static void g();
- };
- };
-
- struct B {
- struct M;
- template <class> struct N;
- static void f();
- template <class> static void g();
- };
-
- struct C {
- template <class> using D = B;
- };
-
- template <class P> struct D {
- template <class U> friend struct P::template D<U>::M;
- // expected-error at -1 {{'test33::C::template D<U>' does not name a class template}}
- };
-
- template struct D<A>;
- template struct D<C>;
- // expected-note at -1 {{in instantiation of template class 'test33::D<test33::C>' requested here}}
-
- template <class P> struct E {
- template <class U> friend struct P::template D<int>::N;
- // expected-error at -1 {{'test33::C::template D<int>' does not name a class template}}
- };
-
- template struct E<A>;
- template struct E<C>;
- // expected-note at -1 {{in instantiation of template class 'test33::E<test33::C>' requested here}}
-
- template <class P> struct F {
- template <class U> friend void P::template D<U>::f();
- // expected-error at -1 {{'test33::C::template D<U>' does not name a class template}}
- };
-
- template struct F<A>;
- template struct F<C>;
- // expected-note at -1 {{in instantiation of template class 'test33::F<test33::C>' requested here}}
-
- template <class P> struct G {
- template <class U> friend void P::template D<int>::g();
- // expected-error at -1 {{'test33::C::template D<int>' does not name a class template}}
- };
-
- template struct G<A>;
- template struct G<C>;
- // expected-note at -1 {{in instantiation of template class 'test33::G<test33::C>' requested here}}
-}
-
-namespace test34 {
- template <class V> class C;
-
- template <class T> struct A {
- template <class U> struct B {
- static void f(C<long> &);
- };
- };
-
- template <class V> class C {
- int n; // #test34-C-n
-
- template <class T>
- friend struct A<T>::template B<V>;
- };
-
- template class C<long>;
-
- template <class T>
- template <class U>
- void A<T>::B<U>::f(C<long> &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test34::C<long>'}}
- // expected-note@#test34-C-n {{implicitly declared private here}}
- }
-
- template struct A<char>::B<long>;
- template struct A<char>::B<int>;
- // expected-note at -1 {{in instantiation of member function 'test34::A<char>::B<int>::f' requested here}}
-}
-
-namespace test35 {
- template <class V> class B;
-
- template <class T> struct A {
- template <class U, class V> static void f(B<V> &);
- };
-
- template <class V> class B {
- int n; // #test35-B-n
-
- template <class T>
- friend void A<T>::template f<int, V>(B &);
- };
-
- template <class T>
- template <class U, class V>
- void A<T>::f(B<V> &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test35::B<long>'}}
- // expected-note@#test35-B-n {{implicitly declared private here}}
- }
-
- template class B<long>;
- template void A<char>::f<int, long>(B<long> &);
- template void A<char>::f<double, long>(B<long> &);
- // expected-note at -1 {{in instantiation of function template specialization 'test35::A<char>::f<double, long>' requested here}}
-}
-
-namespace test36 {
- template <class V> class B;
-
- template <class T> struct A {
- template <class U, class V> static void f(B<V> &, U);
- };
-
- template <class V> class B {
- int n; // #test36-B-n
-
- template <class T>
- friend void A<T>::f(B &, int);
- };
-
- template <class T>
- template <class U, class V>
- void A<T>::f(B<V> &x, U) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test36::B<long>'}}
- // expected-note@#test36-B-n {{implicitly declared private here}}
- }
-
- template class B<long>;
- template void A<char>::f<int, long>(B<long> &, int);
- template void A<char>::f<double, long>(B<long> &, double);
- // expected-note at -1 {{in instantiation of function template specialization 'test36::A<char>::f<double, long>' requested here}}
-}
-
-namespace test37 {
- class C;
-
- template <class T> struct A {
- template <class U> struct B;
- };
-
- template <> struct A<int> {
- template <class U> struct B {
- static void f(C &);
- };
- };
-
- class C {
- int n; // #test37-C-n
-
- template <class T>
- friend struct A<T>::B<long>;
- };
-
- template <class U>
- void A<int>::B<U>::f(C &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test37::C'}}
- // expected-note@#test37-C-n {{implicitly declared private here}}
- }
-
- template struct A<int>::B<long>;
- template struct A<int>::B<double>;
- // expected-note at -1 {{in instantiation of member function 'test37::A<int>::B<double>::f' requested here}}
-}
-
-namespace test38 {
- class B;
-
- template <class T> struct A {
- template <class U> static void f(B &);
- };
-
- template <> struct A<int> {
- template <class U> static void f(B &);
- };
-
- class B {
- int n; // #test38-B-n
-
- template <class T>
- friend void A<T>::f<long>(B &);
- };
-
- template <class U>
- void A<int>::f(B &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test38::B'}}
- // expected-note@#test38-B-n {{implicitly declared private here}}
- }
-
- template void A<int>::f<long>(B &);
- template void A<int>::f<double>(B &);
- // expected-note at -1 {{in instantiation of function template specialization 'test38::A<int>::f<double>' requested here}}
-}
-
-namespace test39 {
- class D;
-
- template <class T> struct A {
- template <class U> struct B;
- };
-
- template <> struct A<int> {
- struct B {
- static void f(D &);
- };
- };
-
- template <> struct A<long> {
- template <class U> union B {
- static void f(D &);
- };
- };
-
- template <> struct A<char> {
- template <class U> struct C {
- static void f(D &);
- };
- };
-
- class D {
- int n; // #test39-D-n
-
- template <class T>
- friend struct A<T>::B<double>;
- };
-
- void A<int>::B::f(D &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test39::D'}}
- // expected-note@#test39-D-n {{implicitly declared private here}}
- }
-
- template <class U>
- void A<long>::B<U>::f(D &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test39::D'}}
- // expected-note@#test39-D-n {{implicitly declared private here}}
- }
-
- template <class U>
- void A<char>::C<U>::f(D &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test39::D'}}
- // expected-note@#test39-D-n {{implicitly declared private here}}
- }
-}
-
-namespace test40 {
- template <class> class C;
-
- template <class T> struct A {
- template <class U> struct B;
- };
-
- template <> struct A<int> {
- struct B { // expected-note {{previous definition is here}}
- static void f(C<int> &);
- };
- };
-
- template <> struct A<long> {
- template <class U> struct B {
- static void f(C<long> &);
- };
- };
-
- template <class V> class C {
- int n; // #test40-C-n
-
- template <class U>
- friend struct A<V>::B; // expected-error {{redefinition of 'B' as
diff erent kind of symbol}}
- };
-
- template class C<int>;
- // expected-note at -1 {{in instantiation of template class 'test40::C<int>' requested here}}
-
- void A<int>::B::f(C<int> &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test40::C<int>'}}
- // expected-note@#test40-C-n {{implicitly declared private here}}
- }
-
- template class C<long>;
-
- template <class U>
- void A<long>::B<U>::f(C<long> &x) {
- x.n = 0;
- }
-
- template struct A<long>::B<double>;
-}
-
-namespace test41 {
- class C;
-
- template <class T> struct A {
- struct B;
- };
-
- template <> struct A<int> {
- template <class U> struct B {
- static void f(C &);
- };
- };
-
- class C {
- int n; // #test41-C-n
-
- template <class T>
- friend struct A<T>::B;
- };
-
- template <class U>
- void A<int>::B<U>::f(C &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test41::C'}}
- // expected-note@#test41-C-n {{implicitly declared private here}}
- }
-
- template struct A<int>::B<double>;
-}
-
-namespace test42 {
- template <class> class D;
-
- struct A {
- template <class U> struct B {
- struct C {
- static void f(D<A> &);
- };
- static void g(D<A> &);
- };
- };
-
- template <class T> class D {
- int n;
-
- template <class U>
- friend struct T::template B<U>::C;
-
- template <class U>
- friend void T::template B<U>::g(D &);
- };
-
- template <class U>
- void A::B<U>::C::f(D<A> &x) {
- x.n = 0;
- }
-
- template <class U>
- void A::B<U>::g(D<A> &x) {
- x.n = 0;
- }
-
- template struct A::B<int>;
-}
-
-namespace test43 {
- template <class T> struct A {
- static void f(typename T::type);
- };
-
- class B {
- using type = int;
- int n;
-
- template <class T> friend void A<T>::f(typename T::type);
- };
-
- template <> struct A<B> {
- static void f(int);
- };
-
- void A<B>::f(int) {
- B b;
- b.n = 0;
- }
-}
diff --git a/clang/test/CXX/temp/temp.decls/temp.friend/p6.cpp b/clang/test/CXX/temp/temp.decls/temp.friend/p6.cpp
deleted file mode 100644
index f60f3dd42445c..0000000000000
--- a/clang/test/CXX/temp/temp.decls/temp.friend/p6.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-template <class T> struct A;
-template <class T> struct B {
- void f();
-};
-
-void t1() {
- struct S {
- template <class T> friend void f();
- // expected-error at -1 {{templates can only be declared in namespace or class scope}}
- };
-}
-
-void t2() {
- struct S {
- template <class T> friend struct A;
- // expected-error at -1 {{templates cannot be declared inside of a local class}}
- };
-}
-
-void t3() {
- struct S {
- template <class T> friend void B<T>::f();
- // expected-error at -1 {{templates cannot be declared inside of a local class}}
- };
-}
diff --git a/clang/test/Index/load-dependent-friend-template.cpp b/clang/test/Index/load-dependent-friend-template.cpp
deleted file mode 100644
index 855ebd3d95d07..0000000000000
--- a/clang/test/Index/load-dependent-friend-template.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: c-index-test -test-load-source all -std=c++20 %s | FileCheck %s
-
-template <class T> struct A {
- struct B;
-};
-
-struct C {
- template <class T> friend struct A<T>::B;
-};
-
-// CHECK: load-dependent-friend-template.cpp:7:8: StructDecl=C:7:8 (Definition)
-// CHECK: load-dependent-friend-template.cpp:8:42: FriendDecl=:8:42
-// CHECK-NEXT: load-dependent-friend-template.cpp:8:19: TemplateTypeParameter=T:8:19 (Definition)
-// CHECK-NEXT: load-dependent-friend-template.cpp:8:36: TemplateRef=A:3:27
-// CHECK-NEXT: load-dependent-friend-template.cpp:8:38: TypeRef=T:8:19
diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp
index 7f86b5574d78b..f22f3c71f44d2 100644
--- a/clang/test/Modules/odr_hash.cpp
+++ b/clang/test/Modules/odr_hash.cpp
@@ -2631,32 +2631,6 @@ S5 s5;
// expected-note at first.h:* {{but in 'FirstModule' found friend function 'T5a'}}
#endif
-#if defined(FIRST) || defined(SECOND)
-template <class T> struct A {
- struct B;
-};
-#endif
-
-#if defined(FIRST)
-struct S6 {
- template <class T>
- requires true
- friend struct A<T>::B;
-};
-#elif defined(SECOND)
-struct S6 {
- template <class T>
- requires(sizeof(T) > 0)
- friend struct A<T>::B;
-};
-#else
-S6 s6;
-// expected-error at second.h:* {{'Friend::S6' has
diff erent definitions in
diff erent modules}}
-// expected-note at second.h:* {{in first definition, possible
diff erence is here}}
-// expected-note at first.h:* {{definition in module 'FirstModule' is here}}
-// expected-note at first.h:* {{in second definition, possible
diff erence is here}}
-#endif
-
#define DECLS \
friend class FriendA; \
friend struct FriendB; \
diff --git a/clang/test/Parser/cxx2c-variadic-friends.cpp b/clang/test/Parser/cxx2c-variadic-friends.cpp
index 951eb47099919..621ae912c1ac9 100644
--- a/clang/test/Parser/cxx2c-variadic-friends.cpp
+++ b/clang/test/Parser/cxx2c-variadic-friends.cpp
@@ -30,7 +30,6 @@ struct E { template<class T> class Nested; };
template<class... Ts> // expected-note {{template parameter is declared here}}
struct VS {
friend Ts...;
- friend Ts...[0];
friend class Ts...; // expected-error {{declaration of 'Ts' shadows template parameter}}
// expected-error at -1 {{pack expansion does not contain any unexpanded parameter packs}}
@@ -57,15 +56,13 @@ struct VS {
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...;
+ 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...;
-
- template<class T>
- friend class Ts...[0]::Nested...;
- // expected-error at -1 {{a pack indexing specifier cannot be used in a nested name specifier of a friend declaration}}
+ 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 {
diff --git a/clang/test/SemaCXX/cxx2c-variadic-friends.cpp b/clang/test/SemaCXX/cxx2c-variadic-friends.cpp
index 910b7be9190d7..0b01907c8c722 100644
--- a/clang/test/SemaCXX/cxx2c-variadic-friends.cpp
+++ b/clang/test/SemaCXX/cxx2c-variadic-friends.cpp
@@ -154,60 +154,3 @@ void f() {
}
}
-namespace GH104057 {
-template <class... Vs> class C;
-
-template <class T> struct A {
- template <class U> struct B {
- static void f(C<int, long> &);
- };
-};
-
-template <class... Vs> class C {
- int n; // #GH104057-C-n
-
- template <class T>
- friend struct A<T>::template B<Vs>...;
-};
-
-template <class T>
-template <class U>
-void A<T>::B<U>::f(C<int, long> &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'GH104057::C<int, long>'}}
- // expected-note@#GH104057-C-n {{implicitly declared private here}}
-}
-
-template struct A<char>::B<int>;
-template struct A<char>::B<long>;
-template struct A<char>::B<double>;
-// expected-note at -1 {{in instantiation of member function 'GH104057::A<char>::B<double>::f' requested here}}
-template <class...> class D;
-
-template <class T> struct E { // expected-note {{candidate friend template ignored: could not match 'long' against 'char'}}
- template <class U> struct F {
- static void f(D<int, long> &);
- };
-};
-
-template <class... Vs> class D {
- int n; // #GH104057-D-n
-
- template <class U>
- friend struct E<Vs>::F...;
-};
-
-template <class T>
-template <class U>
-void E<T>::F<U>::f(D<int, long> &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'GH104057::D<int, long>'}}
- // expected-note@#GH104057-D-n {{implicitly declared private here}}
-}
-
-template struct D<int, long>;
-template struct E<int>::F<char>;
-template struct E<long>::F<double>;
-template struct E<char>::F<float>;
-// expected-note at -1 {{in instantiation of member function 'GH104057::E<char>::F<float>::f' requested here}}
-}
diff --git a/clang/test/SemaCXX/many-template-parameter-lists.cpp b/clang/test/SemaCXX/many-template-parameter-lists.cpp
index 975803ed26bc1..f98005c7e6fb5 100644
--- a/clang/test/SemaCXX/many-template-parameter-lists.cpp
+++ b/clang/test/SemaCXX/many-template-parameter-lists.cpp
@@ -5,7 +5,7 @@
template <class T>
struct X {
template <class U>
- struct A {
+ struct A { // expected-note {{not-yet-instantiated member is declared here}}
template <class V>
struct B {
template <class W>
@@ -22,16 +22,15 @@ struct X {
};
};
- template <class U> // expected-note {{non-deducible template parameter 'U'}}
- template <class V> // expected-note {{non-deducible template parameter 'V'}}
- template <class W> // expected-note {{non-deducible template parameter 'W'}}
- template <class X> // expected-note {{non-deducible template parameter 'X'}}
+ template <class U>
+ template <class V>
+ template <class W>
+ template <class X>
template <class Y>
template <class Z>
- friend void A<U>::template B<V>::template C<W>::template D<X>::template E<Y>::operator+=(Z);
- // expected-error at -1 {{template parameters of friend declaration cannot be deduced from 'A<U>::template B<V>::template C<W>::template D<X>::template E<Y>'}}
+ friend void A<U>::template B<V>::template C<W>::template D<X>::template E<Y>::operator+=(Z); // expected-warning {{not supported}} expected-error {{no member 'A' in 'X<int>'; it has not yet been instantiated}}
};
void test() {
- X<int>::A<int>::B<int>::C<int>::D<int>::E<int>() += 1.0;
+ X<int>::A<int>::B<int>::C<int>::D<int>::E<int>() += 1.0; // expected-note {{in instantiation of template class 'X<int>' requested here}}
}
diff --git a/clang/test/SemaTemplate/GH71595.cpp b/clang/test/SemaTemplate/GH71595.cpp
index c5c5d13036233..daec9410e547a 100644
--- a/clang/test/SemaTemplate/GH71595.cpp
+++ b/clang/test/SemaTemplate/GH71595.cpp
@@ -18,21 +18,17 @@ void f() {
template<class A>
class temp {
template<C<temp> T>
- friend void g();
- // expected-error at -1 {{friend declaration with a constraint that depends on an enclosing template parameter must be a definition}}
+ friend void g(); // expected-error {{friend declaration with a constraint that depends on an enclosing template parameter must be a definition}}
- temp(); // #temp-ctor
+ temp();
};
template<C<temp<int>> T>
void g() {
auto v = temp<T>();
- // expected-error at -1 {{calling a private constructor of class 'temp<int>'}}
- // expected-note@#temp-ctor {{implicitly declared private here}}
}
void h() {
f<int>();
g<int>();
- // expected-note at -1 {{in instantiation of function template specialization 'g<int>' requested here}}
}
diff --git a/clang/test/SemaTemplate/concepts-friends.cpp b/clang/test/SemaTemplate/concepts-friends.cpp
index 7fc0f043dd9a4..11287aa773b1b 100644
--- a/clang/test/SemaTemplate/concepts-friends.cpp
+++ b/clang/test/SemaTemplate/concepts-friends.cpp
@@ -566,61 +566,3 @@ struct Test {
};
}
-
-namespace GH104057 {
-template <class T> concept A = requires { typename T::type; }; // #GH104057_A
-
-struct B {
- using type = int;
-};
-struct C {};
-
-template <class T> struct D {
- static void f()
- requires A<T>; // #GH104057_D_f
-};
-
-class E {
- static int n;
- template <A T> friend void D<T>::f();
-};
-
-template <class T> struct F {
- template <A U> // #GH104057_F_TPL
- static void f() // #GH104057_F_f
- requires A<T>;
-};
-
-class G {
- static int n;
- template <A T> template <A U>
- friend void F<T>::f()
- requires A<T>;
-};
-
-template <class T>
-void D<T>::f() requires A<T> {
- E::n = 0;
-}
-
-template <class T>
-template <A U>
-void F<T>::f() requires A<T> {
- G::n = 0;
-}
-
-void test() {
- D<B>::f();
- D<C>::f();
- // expected-error at -1 {{invalid reference to function 'f': constraints not satisfied}}
- // expected-note@#GH104057_D_f {{because 'GH104057::C' does not satisfy 'A'}}
- // expected-note@#GH104057_A {{because 'typename T::type' would be invalid: no type named 'type' in 'GH104057::C'}}
-
- F<B>::f<B>();
- F<B>::f<C>();
- // expected-error at -1 {{no matching function for call to 'f'}}
- // expected-note@#GH104057_F_f {{candidate template ignored: constraints not satisfied}}
- // expected-note@#GH104057_F_TPL {{because 'GH104057::C' does not satisfy 'A'}}
- // expected-note@#GH104057_A {{because 'typename T::type' would be invalid: no type named 'type' in 'GH104057::C'}}
-}
-} // namespace GH104057
diff --git a/clang/test/SemaTemplate/ctad.cpp b/clang/test/SemaTemplate/ctad.cpp
index 2681ee2a6081e..7a8a72a62e992 100644
--- a/clang/test/SemaTemplate/ctad.cpp
+++ b/clang/test/SemaTemplate/ctad.cpp
@@ -19,31 +19,27 @@ namespace pr41427 {
namespace Access {
struct B {
protected:
- struct type {}; // #Access-B-type
+ struct type {};
};
- template<typename T> struct D : B { // #Access-D
- D(T, typename T::type); // #Access-D-ctor
- // expected-error at -1 {{'type' is a private member of 'Access::Y'}}
- // expected-note@#Access-Y-type {{implicitly declared private here}}
- // expected-note@#Access-D-ctor {{implicit deduction guide declared as 'template <typename T> D(T, typename T::type) -> Access::D<T>'}}
+ template<typename T> struct D : B { // expected-note {{not viable}} \
+ expected-note {{implicit deduction guide declared as 'template <typename T> D(Access::D<T>) -> Access::D<T>'}}
+ D(T, typename T::type); // expected-note {{private member}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename T> D(T, typename T::type) -> Access::D<T>'}}
};
D b = {B(), {}};
class X {
using type = int;
};
- D x = {X(), {}};
- // expected-error at -1 {{no viable constructor or deduction guide}}
- // expected-note@#Access-D {{implicit deduction guide declared as 'template <typename T> D(Access::D<T>) -> Access::D<T>'}}
- // expected-note@#Access-D {{candidate function template not viable: requires 1 argument, but 2 were provided}}
- // expected-note@#Access-D-ctor {{candidate template ignored: substitution failure [with T = X]: 'type' is a private member of 'Access::X'}}
+ D x = {X(), {}}; // expected-error {{no viable constructor or deduction guide}}
+ // Once we implement proper support for dependent nested name specifiers in
+ // friends, this should still work.
class Y {
- template <typename T> friend D<T>::D(T, typename T::type);
- struct type {}; // #Access-Y-type
+ template <typename T> friend D<T>::D(T, typename T::type); // expected-warning {{dependent nested name specifier}}
+ struct type {};
};
D y = {Y(), {}};
- // expected-note at -1 {{in instantiation of template class 'Access::D<Access::Y>' requested here}}
class Z {
template <typename T> friend class D;
diff --git a/clang/test/SemaTemplate/dependent-friend-constraints.cpp b/clang/test/SemaTemplate/dependent-friend-constraints.cpp
deleted file mode 100644
index d4aeb7180deb5..0000000000000
--- a/clang/test/SemaTemplate/dependent-friend-constraints.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
-
-namespace test0 {
- class C;
-
- template <class T> struct A { // #test0-A
- struct B {
- static void f(C &);
- };
- };
-
- class C {
- int n; // #test0-C-n
- template <class T>
- requires __is_same(T, int) // #test0-requires
- friend struct A<T>::B;
- };
-
- template <class T> void A<T>::B::f(C &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test0::C'}}
- // expected-note@#test0-C-n {{implicitly declared private here}}
- // expected-note@#test0-A {{candidate template ignored: constraints not satisfied [with T = double]}}
- // expected-note@#test0-requires {{because '__is_same(double, int)' evaluated to false}}
- }
-
- template void A<int>::B::f(C &);
- template void A<double>::B::f(C &);
- // expected-note at -1 {{in instantiation of member function 'test0::A<double>::B::f' requested here}}
-}
-
-namespace test1 {
- class C;
-
- template <class T> struct A {
- template <class U>
- requires __is_same(T, U)
- struct B;
- };
-
- class C {
- int n;
- template <class T>
- template <class U>
- requires __is_same(T, U)
- friend struct A<T>::B;
- };
-
- template <> struct A<int> {
- template <class U>
- requires __is_same(int, U)
- struct B {
- static void f(C &x) { x.n = 0; }
- };
- };
-
- template struct A<int>::B<int>;
-}
-
-namespace test2 {
- class C;
-
- template <class T> struct A {
- template <class U>
- requires __is_same(T, U)
- struct B;
- };
-
- class C {
- int n; // #test2-C-n
- template <class T>
- template <class U>
- requires __is_same(T, U)
- friend struct A<T>::B;
- };
-
- template <> struct A<int> {
- template <class U>
- requires (sizeof(U) != 0)
- struct B {
- static void f(C &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test2::C'}}
- // expected-note@#test2-C-n {{implicitly declared private here}}
- }
- };
- };
-
- template struct A<int>::B<int>;
-}
-
-namespace test3 {
- class B;
-
- template <class T> struct A {
- template <class U>
- requires __is_same(T, U)
- static void f(B &);
- };
-
- class B {
- int n;
- template <class T>
- template <class U>
- requires __is_same(T, U)
- friend void A<T>::f(B &);
- };
-
- template <> struct A<int> {
- template <class U>
- requires __is_same(int, U)
- static void f(B &x) {
- x.n = 0;
- }
- };
-
- template void A<int>::f<int>(B &);
-}
-
-namespace test4 {
- class B;
-
- template <class T> struct A {
- template <class U>
- requires __is_same(T, U)
- static void f(B &);
- };
-
- class B {
- int n; // #test4-B-n
- template <class T>
- template <class U>
- requires __is_same(T, U)
- friend void A<T>::f(B &);
- };
-
- template <> struct A<int> {
- template <class U>
- requires (sizeof(U) != 0)
- static void f(B &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test4::B'}}
- // expected-note@#test4-B-n {{implicitly declared private here}}
- }
- };
-
- template void A<int>::f<int>(B &);
-}
-
-namespace test5 {
- class B;
-
- template <class T> struct A {
- template <class U>
- static void f(B &) requires (sizeof(U) != 0);
- };
-
- class B {
- int n;
- template <class T>
- template <class U>
- friend void A<T>::f(B &) requires (sizeof(U) != 0);
- };
-
- template <> struct A<int> {
- template <class U>
- static void f(B &x) requires (sizeof(U) != 0) {
- x.n = 0;
- }
- };
-
- template void A<int>::f<int>(B &);
-}
-
-namespace test6 {
- class B;
-
- template <class T> struct A {
- template <class U>
- static void f(B &) requires (sizeof(U) != 0);
- };
-
- class B {
- int n; // #test6-B-n
- template <class T>
- template <class U>
- friend void A<T>::f(B &) requires (sizeof(U) != 0);
- };
-
- template <> struct A<int> {
- template <class U>
- static void f(B &x) requires (sizeof(U) > 1) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test6::B'}}
- // expected-note@#test6-B-n {{implicitly declared private here}}
- }
- };
-
- template void A<int>::f<int>(B &);
-}
-
-namespace test7 {
- template <class T> struct A; // #test7-A
-
- template <class V> class C {
- int n; // #test7-C-n
- template <class T>
- requires __is_same(T, V) // #test7-requires
- friend struct A<T>::B;
- };
-
- template <> struct A<int> {
- struct B {
- static void f(C<int> &x) { x.n = 0; }
- };
- };
-
- template <> struct A<double> {
- struct B {
- static void f(C<int> &x) {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test7::C<int>'}}
- // expected-note@#test7-C-n {{implicitly declared private here}}
- // expected-note@#test7-A {{candidate template ignored: constraints not satisfied [with T = double]}}
- // expected-note@#test7-requires {{because '__is_same(double, int)' evaluated to false}}
- }
- };
- };
-}
-
-namespace test8 {
- template <class T, class U>
- concept Same = __is_same(T, U);
-
- class B;
-
- template <class T> struct A {
- template <class U>
- static void f(B &) requires Same<T, T>;
- };
-
- template <> struct A<int> {
- template <class U>
- static void f(B &) requires Same<U, U>;
- };
-
- class B {
- int n; // #test8-B-n
-
- template <class T>
- template <class U>
- friend void A<T>::f(B &) requires Same<T, T>;
- };
-
- template <class U>
- void A<int>::f(B &x) requires Same<U, U> {
- x.n = 0;
- // expected-error at -1 {{'n' is a private member of 'test8::B'}}
- // expected-note@#test8-B-n {{implicitly declared private here}}
- }
-
- template void A<int>::f<double>(B &);
-}
diff --git a/clang/test/SemaTemplate/friend-template.cpp b/clang/test/SemaTemplate/friend-template.cpp
index 05ab57cebfec8..2b5a226c3b33c 100644
--- a/clang/test/SemaTemplate/friend-template.cpp
+++ b/clang/test/SemaTemplate/friend-template.cpp
@@ -111,31 +111,6 @@ namespace test5 {
};
}
-namespace GH104057 {
-template <class T>
-struct A { // #GH104057-A
- template <class> struct B;
-
-private:
- static void f(); // #GH104057-A-f
- template <class U> friend struct A<U *>::B;
-};
-
-template <class T>
-template <class U> struct A<T>::B {
- static void g() {
- A<int>::f();
- // expected-error at -1 {{'f' is a private member of 'GH104057::A<int>'}}
- // expected-note@#GH104057-A-f {{declared private here}}
- // expected-note@#GH104057-A {{candidate friend template ignored: could not match 'U *' against 'double'}}
- }
-};
-
-void test() {
- A<double>::B<int>::g(); // expected-note {{in instantiation of member function 'GH104057::A<double>::B<int>::g' requested here}}
-}
-}
-
// PR6022
namespace PR6022 {
template <class T1, class T2 , class T3 > class A;
@@ -260,19 +235,20 @@ namespace rdar11147355 {
template <class T>
struct A {
template <class U> class B;
- template <class S> template <class U> friend class A<S>::B;
+ template <class S> template <class U> friend class A<S>::B; // expected-warning {{dependent nested name specifier 'A<S>' for friend template declaration is not supported; ignoring this friend declaration}}
private:
- int n;
+ int n; // expected-note {{here}}
};
template <class S> template <class U> class A<S>::B {
public:
- int f(A<S*> a) { return a.n; }
+ // FIXME: This should be permitted.
+ int f(A<S*> a) { return a.n; } // expected-error {{private}}
};
A<double>::B<double> ab;
A<double*> a;
- int k = ab.f(a);
+ int k = ab.f(a); // expected-note {{instantiation of}}
}
namespace RedeclUnrelated {
diff --git a/clang/test/SemaTemplate/nested-template.cpp b/clang/test/SemaTemplate/nested-template.cpp
index fcf9a1d647ab9..b5da1b1c3ccd4 100644
--- a/clang/test/SemaTemplate/nested-template.cpp
+++ b/clang/test/SemaTemplate/nested-template.cpp
@@ -168,17 +168,3 @@ namespace RefPack {
int arr[10];
void g() { A<k>().f(arr); }
}
-
-namespace GH104057 {
- template <class T>
- struct A {
- template <bool> struct B {};
- };
-
- template <class T>
- struct C {
- using type = typename A<T>::template B<true>;
- };
-
- A<int>::B<true> *p = (C<int>::type *)0;
-}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 47d6d2cb51efd..e485e6e2e5547 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -1312,14 +1312,6 @@ bool CursorVisitor::VisitFriendDecl(FriendDecl *D) {
return false;
}
-bool CursorVisitor::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
- for (TemplateParameterList *TPL : D->getTemplateParameterLists())
- if (VisitTemplateParameters(TPL))
- return true;
-
- return VisitFriendDecl(D);
-}
-
bool CursorVisitor::VisitDecompositionDecl(DecompositionDecl *D) {
for (auto *B : D->bindings()) {
if (Visit(MakeCXCursor(B, TU, RegionOfInterest)))
diff --git a/clang/tools/libclang/CursorVisitor.h b/clang/tools/libclang/CursorVisitor.h
index 1b359d2920e11..d5ab699756988 100644
--- a/clang/tools/libclang/CursorVisitor.h
+++ b/clang/tools/libclang/CursorVisitor.h
@@ -248,7 +248,6 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
bool VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
bool VisitStaticAssertDecl(StaticAssertDecl *D);
bool VisitFriendDecl(FriendDecl *D);
- bool VisitFriendTemplateDecl(FriendTemplateDecl *D);
bool VisitDecompositionDecl(DecompositionDecl *D);
bool VisitConceptDecl(ConceptDecl *D);
bool VisitTypeConstraint(const TypeConstraint &TC);
diff --git a/clang/unittests/AST/DeclTest.cpp b/clang/unittests/AST/DeclTest.cpp
index 195b8ab4c4e66..4919977300fb8 100644
--- a/clang/unittests/AST/DeclTest.cpp
+++ b/clang/unittests/AST/DeclTest.cpp
@@ -666,126 +666,6 @@ TEST(Decl, TemplateArgumentDefaulted) {
EXPECT_TRUE(ArgList.get(3).getIsDefaulted());
}
-TEST(Decl, InstantiatedDependentFriendTemplate) {
- StringRef Code = R"cpp(
- template <class T> struct A {
- template <class U> struct B;
- };
-
- template <class T> struct C {
- template <class U> friend struct A<T>::B;
- };
-
- template struct C<int>;
- )cpp";
-
- auto AST = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++20"});
- ASTContext &Ctx = AST->getASTContext();
- const auto *CTemplate = selectFirst<ClassTemplateDecl>(
- "c", match(classTemplateDecl(hasName("C")).bind("c"), Ctx));
- ASSERT_NE(CTemplate, nullptr);
-
- const FriendTemplateDecl *DependentFriend = nullptr;
- for (const Decl *D : CTemplate->getTemplatedDecl()->decls()) {
- if (const auto *FTD = dyn_cast<FriendTemplateDecl>(D)) {
- DependentFriend = FTD;
- break;
- }
- }
- ASSERT_NE(DependentFriend, nullptr);
- ASSERT_NE(DependentFriend->getFriendType(), nullptr);
- EXPECT_TRUE(DependentFriend->getFriendTemplateName().isDependent());
-
- const auto *CSpecialization = selectFirst<ClassTemplateSpecializationDecl>(
- "c", match(classTemplateSpecializationDecl(hasName("C")).bind("c"), Ctx));
- ASSERT_NE(CSpecialization, nullptr);
-
- const FriendTemplateDecl *InstFriend = nullptr;
- for (const Decl *D : CSpecialization->decls()) {
- if (const auto *FTD = dyn_cast<FriendTemplateDecl>(D)) {
- InstFriend = FTD;
- break;
- }
- }
- ASSERT_NE(InstFriend, nullptr);
- ASSERT_EQ(InstFriend->getFriendType(), nullptr);
- ASSERT_FALSE(InstFriend->getFriendTemplateName().isNull());
-
- const FriendDecl *Friend = InstFriend;
- EXPECT_EQ(Friend->getFriendDecl(),
- InstFriend->getFriendTemplateName().getAsTemplateDecl());
- EXPECT_EQ(InstFriend->getSourceRange().getEnd(), InstFriend->getLocation());
-}
-
-TEST(Decl, InstantiatedDependentFriendTemplateParameters) {
- StringRef Code = R"cpp(
- template <class T> struct A {
- template <class U> struct B;
- };
-
- template <class V> struct C {
- template <class U>
- friend struct A<U>::template B<V>;
- };
-
- template struct C<int>;
- )cpp";
-
- auto AST = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++20"});
- ASTContext &Ctx = AST->getASTContext();
- const auto *CSpecialization = selectFirst<ClassTemplateSpecializationDecl>(
- "c", match(classTemplateSpecializationDecl(hasName("C")).bind("c"), Ctx));
- ASSERT_NE(CSpecialization, nullptr);
- ASSERT_NE(CSpecialization->friend_begin(), CSpecialization->friend_end());
-
- const auto *Friend =
- dyn_cast<FriendTemplateDecl>(*CSpecialization->friend_begin());
- ASSERT_NE(Friend, nullptr);
- ASSERT_EQ(Friend->getTemplateParameterLists().size(), 1u);
- ASSERT_NE(Friend->getFriendType(), nullptr);
-
- TemplateSpecializationTypeLoc FriendTL =
- Friend->getFriendType()
- ->getTypeLoc()
- .castAs<TemplateSpecializationTypeLoc>();
- const Type *QualifierType =
- FriendTL.getQualifierLoc().getNestedNameSpecifier().getAsType();
- ASSERT_NE(QualifierType, nullptr);
- const auto *TST = QualifierType->getAs<TemplateSpecializationType>();
- ASSERT_NE(TST, nullptr);
- const auto *TTP =
- TST->template_arguments()[0].getAsType()->getAs<TemplateTypeParmType>();
- ASSERT_NE(TTP, nullptr);
- EXPECT_EQ(TTP->getDecl(),
- Friend->getTemplateParameterLists().front()->getParam(0));
-}
-
-TEST(Decl, InvalidFunctionFriendIsRetained) {
- StringRef Code = R"cpp(
- int f();
- struct A {
- friend void f();
- };
- )cpp";
-
- IgnoringDiagConsumer Diags;
- auto AST = tooling::buildASTFromCodeWithArgs(
- Code, {"-std=c++20"}, "input.cc", "clang-tool",
- std::make_shared<PCHContainerOperations>(),
- tooling::getClangStripDependencyFileAdjuster(),
- tooling::FileContentMappings(), &Diags);
- ASTContext &Ctx = AST->getASTContext();
- const auto *Record = selectFirst<CXXRecordDecl>(
- "a", match(cxxRecordDecl(hasName("A"), isDefinition()).bind("a"), Ctx));
- ASSERT_NE(Record, nullptr);
- ASSERT_NE(Record->friend_begin(), Record->friend_end());
-
- const FriendDecl *Friend = *Record->friend_begin();
- EXPECT_TRUE(Friend->isInvalidDecl());
- ASSERT_NE(Friend->getFriendDecl(), nullptr);
- EXPECT_TRUE(Friend->getFriendDecl()->isInvalidDecl());
-}
-
TEST(Decl, CXXDestructorDeclsShouldHaveWellFormedNameInfoRanges) {
// GH71161
llvm::Annotations Code(R"cpp(
diff --git a/clang/unittests/AST/StructuralEquivalenceTest.cpp b/clang/unittests/AST/StructuralEquivalenceTest.cpp
index a368474f2841a..24e20c7471f3c 100644
--- a/clang/unittests/AST/StructuralEquivalenceTest.cpp
+++ b/clang/unittests/AST/StructuralEquivalenceTest.cpp
@@ -863,25 +863,6 @@ TEST_F(StructuralEquivalenceRecordTest, SameFriendsSameOrder) {
EXPECT_TRUE(testStructuralMatch(t));
}
-TEST_F(StructuralEquivalenceRecordTest, InstantiatedFriendTemplates) {
- std::string Code = R"(
- template <class T> struct A {
- template <class U> struct B;
- };
- template <class T> struct C {
- template <class U> friend struct A<T>::B;
- };
- template struct C<int>;
- )";
- auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
- Code, Code, Lang_CXX11, classTemplateSpecializationDecl(hasName("C")));
- ASSERT_NE(get<0>(Decls)->friend_begin(), get<0>(Decls)->friend_end());
- auto *Friend = dyn_cast<FriendTemplateDecl>(*get<0>(Decls)->friend_begin());
- ASSERT_NE(Friend, nullptr);
- ASSERT_EQ(Friend->getFriendType(), nullptr);
- EXPECT_TRUE(testStructuralMatch(Decls));
-}
-
struct StructuralEquivalenceLambdaTest : StructuralEquivalenceTest {};
TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithDifferentMethods) {
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index ec29200198554..a2a96f470d94a 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -4516,7 +4516,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td>[<a href="https://wg21.link/temp.friend">temp.friend</a>]</td>
<td>CD2</td>
<td>Explicit specialization and friendship</td>
- <td class="unreleased" align="center">Clang 24</td>
+ <td class="none" align="center">No</td>
</tr>
<tr id="639">
<td><a href="https://cplusplus.github.io/CWG/issues/639.html">639</a></td>
@@ -12819,7 +12819,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td>[<a href="https://wg21.link/temp.friend">temp.friend</a>]</td>
<td>CD5</td>
<td>Determining “corresponding members” for friendship</td>
- <td class="unreleased" align="center">Clang 24</td>
+ <td class="none" align="center">No</td>
</tr>
<tr id="1863">
<td><a href="https://cplusplus.github.io/CWG/issues/1863.html">1863</a></td>
@@ -13215,7 +13215,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td>[<a href="https://wg21.link/temp.friend">temp.friend</a>]</td>
<td>CD5</td>
<td><TT>friend</TT> templates with dependent scopes</td>
- <td class="unreleased" align="center">Clang 24</td>
+ <td class="none" align="center">No</td>
</tr>
<tr class="open" id="1919">
<td><a href="https://cplusplus.github.io/CWG/issues/1919.html">1919</a></td>
@@ -13404,7 +13404,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td>[<a href="https://wg21.link/temp.friend">temp.friend</a>]</td>
<td>CD5</td>
<td>Friend declarations naming members of class templates in non-templates</td>
- <td class="unreleased" align="center">Clang 24</td>
+ <td class="none" align="center">No</td>
</tr>
<tr id="1946">
<td><a href="https://cplusplus.github.io/CWG/issues/1946.html">1946</a></td>
More information about the llvm-branch-commits
mailing list