[clang] [clang-tools-extra] Revert "[Clang] support friend declarations with a dependent nested-name-specifier" (PR #208302)
Oleksandr Tarasiuk via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 8 12:53:58 PDT 2026
https://github.com/a-tarasyuk created https://github.com/llvm/llvm-project/pull/208302
Reverts llvm/llvm-project#191268
---
Revert dependent friend support due to a crash in access checking https://github.com/llvm/llvm-project/issues/208290
>From 372ff7bd46045385890e77d04da0862631c7fd9f Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.tarasiuk at outlook.com>
Date: Wed, 8 Jul 2026 22:19:57 +0300
Subject: [PATCH] =?UTF-8?q?Revert=20"[Clang]=20support=20friend=20declarat?=
=?UTF-8?q?ions=20with=20a=20dependent=20nested-name-spec=E2=80=A6"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This reverts commit dcf1b8f2c00b38777f71297afc7b575cd2d9300a.
---
clang-tools-extra/clang-doc/Serialize.cpp | 3 +
clang/docs/ReleaseNotes.md | 1 -
.../clang/AST/ASTStructuralEquivalence.h | 2 -
clang/include/clang/AST/DeclFriend.h | 125 ++-
clang/include/clang/AST/DeclTemplate.h | 82 +-
clang/include/clang/AST/RecursiveASTVisitor.h | 16 +-
clang/include/clang/Basic/DeclNodes.td | 2 +-
clang/include/clang/Basic/DiagnosticGroups.td | 1 +
.../clang/Basic/DiagnosticSemaKinds.td | 17 +-
clang/include/clang/Sema/Sema.h | 12 -
clang/include/clang/Sema/Template.h | 11 +-
clang/include/clang/Sema/TemplateDeduction.h | 17 +-
.../include/clang/Serialization/ASTBitCodes.h | 7 -
clang/lib/AST/ASTImporter.cpp | 110 +--
clang/lib/AST/ASTStructuralEquivalence.cpp | 59 +-
clang/lib/AST/DeclFriend.cpp | 64 +-
clang/lib/AST/DeclPrinter.cpp | 36 +-
clang/lib/AST/DeclTemplate.cpp | 55 +-
clang/lib/AST/ODRHash.cpp | 15 -
clang/lib/Sema/Sema.cpp | 5 +-
clang/lib/Sema/SemaAccess.cpp | 749 +++---------------
clang/lib/Sema/SemaDeclCXX.cpp | 229 +++---
clang/lib/Sema/SemaOverload.cpp | 24 +-
clang/lib/Sema/SemaTemplate.cpp | 10 +-
clang/lib/Sema/SemaTemplateDeduction.cpp | 10 -
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 201 ++---
clang/lib/Serialization/ASTReaderDecl.cpp | 30 +-
clang/lib/Serialization/ASTWriterDecl.cpp | 35 +-
.../class.access/class.friend/p3-cxx0x.cpp | 4 +-
clang/test/CXX/drs/cwg18xx.cpp | 16 +-
clang/test/CXX/drs/cwg19xx.cpp | 11 +-
clang/test/CXX/drs/cwg28xx.cpp | 3 +-
clang/test/CXX/drs/cwg6xx.cpp | 19 +-
.../CXX/temp/temp.decls/temp.friend/p5.cpp | 267 +------
.../CXX/temp/temp.decls/temp.friend/p6.cpp | 27 -
clang/test/Parser/cxx2c-variadic-friends.cpp | 6 +-
.../SemaCXX/many-template-parameter-lists.cpp | 9 +-
clang/test/SemaTemplate/GH71595.cpp | 8 +-
clang/test/SemaTemplate/concepts-friends.cpp | 58 --
clang/test/SemaTemplate/ctad.cpp | 24 +-
clang/test/SemaTemplate/friend-template.cpp | 34 +-
41 files changed, 592 insertions(+), 1822 deletions(-)
delete mode 100644 clang/test/CXX/temp/temp.decls/temp.friend/p6.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 b49a9db3d5fca..0626c41774960 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -246,7 +246,6 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
- `__is_trivially_equality_comparable` no longer returns false for all enum types. (#GH132672)
- `auto` parameters are now available in all C++ language modes as an extension.
-- Clang now supports friend declarations with a dependent nested name specifier. (#GH104057)
#### C++2d Feature Support
diff --git a/clang/include/clang/AST/ASTStructuralEquivalence.h b/clang/include/clang/AST/ASTStructuralEquivalence.h
index 89d7f8d6ba8ff..6f82de1ae136d 100644
--- a/clang/include/clang/AST/ASTStructuralEquivalence.h
+++ b/clang/include/clang/AST/ASTStructuralEquivalence.h
@@ -135,8 +135,6 @@ struct StructuralEquivalenceContext {
/// \c VisitedDecls members) and can cause faulty equivalent results.
bool IsEquivalent(Stmt *S1, Stmt *S2);
- bool IsEquivalent(TemplateParameterList *TPL1, TemplateParameterList *TPL2);
-
/// Find the index of the given anonymous struct/union within its
/// context.
///
diff --git a/clang/include/clang/AST/DeclFriend.h b/clang/include/clang/AST/DeclFriend.h
index c68028d22bd54..1f8c210263677 100644
--- a/clang/include/clang/AST/DeclFriend.h
+++ b/clang/include/clang/AST/DeclFriend.h
@@ -15,13 +15,20 @@
#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>
namespace clang {
@@ -42,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:
@@ -52,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 FriendL, SourceLocation EllipsisLoc = {})
- : Decl(K, DC, L), EllipsisLoc(EllipsisLoc), FriendLoc(FriendL),
- 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();
@@ -82,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
@@ -96,27 +126,74 @@ 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.
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.
class CXXRecordDecl::friend_iterator {
friend class CXXRecordDecl;
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 95d5ab1b11bf2..4f5a4e1b7b8a6 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"
@@ -2462,51 +2461,45 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
/// 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 *> FriendTypeTPLists,
- TemplateName Template = {})
- : FriendDecl(Decl::FriendTemplate, DC, Loc, Friend, FriendLoc,
- EllipsisLoc),
- NumTPLists(FriendTypeTPLists.size()), Template(Template) {
- llvm::copy(FriendTypeTPLists, getTrailingObjects());
- }
+ // The parameter list.
+ TemplateParameterList **Params = nullptr;
+
+ // The declaration that's a friend of this class.
+ FriendUnion Friend;
+
+ // Location of the 'friend' specifier.
+ SourceLocation FriendLoc;
- FriendTemplateDecl(EmptyShell Empty, unsigned NumFriendTypeTPLists)
- : FriendDecl(Decl::FriendTemplate, Empty),
- NumTPLists(NumFriendTypeTPLists) {}
+ 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) {}
+
+ FriendTemplateDecl(EmptyShell Empty) : Decl(Decl::FriendTemplate, Empty) {}
public:
friend class ASTDeclReader;
- friend class ASTDeclWriter;
- friend TrailingObjects;
static FriendTemplateDecl *
Create(ASTContext &Context, DeclContext *DC, SourceLocation Loc,
- FriendUnion Friend, SourceLocation FriendLoc,
- ArrayRef<TemplateParameterList *> FriendTypeTPLists = {},
- SourceLocation EllipsisLoc = {});
-
- static FriendTemplateDecl *
- Create(ASTContext &Context, DeclContext *DC, SourceLocation Loc,
- TemplateName Template, SourceLocation FriendLoc,
- ArrayRef<TemplateParameterList *> FriendTypeTPLists = {},
- SourceLocation EllipsisLoc = {});
-
- static FriendTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
- unsigned FriendTypeNumTPLists);
+ MutableArrayRef<TemplateParameterList *> Params, FriendUnion Friend,
+ SourceLocation FriendLoc);
- SourceRange getSourceRange() const override LLVM_READONLY;
+ static FriendTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
/// If this friend declaration names a templated type (or
/// a dependent member type of a templated type), return that
@@ -2519,16 +2512,21 @@ class FriendTemplateDecl final
/// a member function of a templated type), return that type;
/// otherwise return null.
NamedDecl *getFriendDecl() const {
- if (TemplateDecl *TD = Template.getAsTemplateDecl())
- return TD;
- return Friend.dyn_cast<NamedDecl *>();
+ return Friend.dyn_cast<NamedDecl*>();
}
- TemplateName getFriendTemplateName() const { return Template; }
+ /// Retrieves the location of the 'friend' keyword.
+ SourceLocation getFriendLoc() const {
+ return FriendLoc;
+ }
- ArrayRef<TemplateParameterList *>
- getFriendTypeTemplateParameterLists() const {
- return ArrayRef(getTrailingObjects(), NumTPLists);
+ TemplateParameterList *getTemplateParameterList(unsigned i) const {
+ assert(i <= NumParams);
+ return Params[i];
+ }
+
+ unsigned getNumTemplateParameters() const {
+ return NumParams;
}
// Implement isa/cast/dyncast/etc.
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 4552437d3db9a..b77443f1fa0ab 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1733,16 +1733,12 @@ DEF_TRAVERSE_DECL(FriendDecl, {
})
DEF_TRAVERSE_DECL(FriendTemplateDecl, {
- TemplateName Template = D->getFriendTemplateName();
- if (Template.isNull()) {
- if (D->getFriendType())
- TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc()));
- else
- TRY_TO(TraverseDecl(D->getFriendDecl()));
- } else {
- TRY_TO(TraverseTemplateName(Template));
- }
- for (TemplateParameterList *TPL : D->getFriendTypeTemplateParameterLists()) {
+ if (D->getFriendType())
+ TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc()));
+ else
+ TRY_TO(TraverseDecl(D->getFriendDecl()));
+ 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));
diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td
index c55a3d68184f4..ffb58b43812dc 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 Block : DeclNode<Decl, "blocks">, DeclContext;
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index d353a86f228ba..79583534b9bbd 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1198,6 +1198,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 3fa5bce9fb04f..38d9e4046d3a5 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1916,6 +1916,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">,
@@ -1925,8 +1935,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_dependent_friend_not_member : Error<
- "friend declaration does not name a member of a class template specialization">;
def err_invalid_base_in_interface : Error<
"interface type cannot inherit from "
@@ -5282,16 +5290,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
// different 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 differently 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 e658f57968b99..f7d0d493e7081 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -12018,9 +12018,6 @@ class Sema final : public SemaBase {
bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous);
void CompleteMemberSpecialization(NamedDecl *Member, LookupResult &Previous);
- bool CheckDependentFriend(SourceLocation Loc, NestedNameSpecifier NNS,
- TemplateParameterList *FPL);
-
// Explicit instantiation of a class template specialization
DeclResult ActOnExplicitInstantiation(
Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc,
@@ -12754,15 +12751,6 @@ class Sema final : public SemaBase {
return false;
});
- /// Finish template argument deduction for a template declaration, checking
- /// the deduced template arguments for completeness and forming the deduced
- /// template argument list.
- TemplateDeductionResult FinishTemplateArgumentDeduction(
- TemplateDecl *TD, TemplateParameterList *TPL,
- ArrayRef<TemplateArgument> PatternArgs, ArrayRef<TemplateArgument> Args,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- sema::TemplateDeductionInfo &Info, bool CopyDeducedArgs);
-
/// Perform template argument deduction from a function call
/// (C++ [temp.deduct.call]).
///
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 42febace0a671..b0170c21feb1a 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -715,7 +715,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);
@@ -724,10 +724,6 @@ enum class TemplateSubstitutionKind : char {
TemplateParameterList *
SubstTemplateParams(TemplateParameterList *List);
- bool SubstTemplateParameterLists(
- ArrayRef<TemplateParameterList *> TPL,
- SmallVectorImpl<TemplateParameterList *> &InstTPL);
-
bool SubstQualifier(const DeclaratorDecl *OldDecl,
DeclaratorDecl *NewDecl);
bool SubstQualifier(const TagDecl *OldDecl,
@@ -738,11 +734,6 @@ enum class TemplateSubstitutionKind : char {
ArrayRef<TemplateArgument> Converted,
VarTemplateSpecializationDecl *PrevDecl = nullptr);
- template <typename FriendTy>
- bool
- InstantiateFriendPackExpansion(FriendTy *D, TypeSourceInfo *TSI,
- ArrayRef<TemplateParameterList *> TPL = {});
-
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 b581a70a073b5..279380de2f7fe 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -2109,13 +2109,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,
-};
-
/// 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 da1b6c2e908c6..567d2d07298a3 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -538,7 +538,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);
@@ -4561,15 +4560,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);
}
@@ -4589,6 +4592,7 @@ static FriendCountAndPosition getFriendCountAndPosition(ASTImporter &Importer,
}
assert(FriendPosition && "Friend decl not found in own parent.");
+
return {FriendCount, *FriendPosition};
}
@@ -4604,8 +4608,7 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
const auto *RD = cast<CXXRecordDecl>(DC);
SmallVector<FriendDecl *, 2> ImportedEquivalentFriends;
for (FriendDecl *ImportedFriend : RD->friends())
- if (ImportedFriend->getKind() == Decl::Friend &&
- IsEquivalentFriend(Importer, D, ImportedFriend))
+ if (IsEquivalentFriend(Importer, D, ImportedFriend))
ImportedEquivalentFriends.push_back(ImportedFriend);
FriendCountAndPosition CountAndPosition =
@@ -4637,6 +4640,15 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
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)
return LocationOrErr.takeError();
@@ -4650,7 +4662,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());
@@ -4659,92 +4671,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;
- TemplateName ToTemplate;
- TemplateName FromTemplate = D->getFriendTemplateName();
- if (FromTemplate.isNull()) {
- if (NamedDecl *FriendD = D->getFriendDecl()) {
- NamedDecl *ToFriendD;
- if (Error Err = importInto(ToFriendD, FriendD))
- return std::move(Err);
- ToFU = ToFriendD;
- } else {
- if (auto TSIOrErr = import(D->getFriendType()))
- ToFU = *TSIOrErr;
- else
- return TSIOrErr.takeError();
- }
- } else {
- if (auto TemplateOrErr = import(FromTemplate))
- ToTemplate = *TemplateOrErr;
- else
- return TemplateOrErr.takeError();
- }
-
- ArrayRef<TemplateParameterList *> TPLs =
- D->getFriendTypeTemplateParameterLists();
- SmallVector<TemplateParameterList *, 1> ToParams(TPLs.size());
- for (unsigned I = 0, N = TPLs.size(); I != N; ++I) {
- if (auto ParamsOrErr = import(TPLs[I]))
- ToParams[I] = *ParamsOrErr;
- else
- return ParamsOrErr.takeError();
- }
-
- 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 (ToTemplate.isNull()) {
- if (GetImportedOrCreateDecl(FTD, D, Importer.getToContext(), DC,
- *LocationOrErr, ToFU, *FriendLocOrErr, ToParams,
- *EllipsisLocOrErr))
- return FTD;
- } else {
- if (GetImportedOrCreateDecl(FTD, D, Importer.getToContext(), DC,
- *LocationOrErr, ToTemplate, *FriendLocOrErr,
- ToParams, *EllipsisLocOrErr))
- 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 d3b47ebe5520c..e0b62591a6a73 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -2290,8 +2290,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
}
- return IsStructurallyEquivalent(Context, Params1->getRequiresClause(),
- Params2->getRequiresClause());
+ return true;
}
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
@@ -2442,45 +2441,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
}
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- FriendTemplateDecl *FTD1,
- FriendTemplateDecl *FTD2) {
- ArrayRef<TemplateParameterList *> TPL1 =
- FTD1->getFriendTypeTemplateParameterLists();
- ArrayRef<TemplateParameterList *> TPL2 =
- FTD2->getFriendTypeTemplateParameterLists();
- bool EquivalentTemplateParameterLists = llvm::equal(
- TPL1, TPL2,
- [&Context](TemplateParameterList *LHS, TemplateParameterList *RHS) {
- return IsStructurallyEquivalent(Context, LHS, RHS);
- });
- if (!EquivalentTemplateParameterLists)
- return false;
-
- TemplateName TN1 = FTD1->getFriendTemplateName();
- TemplateName TN2 = FTD2->getFriendTemplateName();
- if (TN1.isNull() != TN2.isNull())
- return false;
-
- if (TN1.isNull()) {
- if ((FTD1->getFriendType() && FTD2->getFriendDecl()) ||
- (FTD1->getFriendDecl() && FTD2->getFriendType()))
- return false;
-
- if (FTD1->getFriendDecl() && FTD2->getFriendDecl())
- return IsStructurallyEquivalent(Context, FTD1->getFriendDecl(),
- FTD2->getFriendDecl());
-
- if (FTD1->getFriendType() && FTD2->getFriendType())
- return IsStructurallyEquivalent(Context, FTD1->getFriendType()->getType(),
- FTD2->getFriendType()->getType());
-
- return false;
- }
-
- return IsStructurallyEquivalent(Context, TN1, TN2);
-}
-
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
TypedefNameDecl *D1, TypedefNameDecl *D2) {
if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
@@ -2820,23 +2780,6 @@ bool StructuralEquivalenceContext::CheckCommonEquivalence(Decl *D1, Decl *D2) {
return true;
}
-bool StructuralEquivalenceContext::IsEquivalent(TemplateParameterList *TPL1,
- TemplateParameterList *TPL2) {
- assert(DeclsToCheck.empty());
- assert(VisitedDecls.empty());
-
- if (TPL1 == TPL2)
- return true;
-
- if (!TPL1 || !TPL2)
- return false;
-
- if (!::IsStructurallyEquivalent(*this, TPL1, TPL2))
- return false;
-
- return !Finish();
-}
-
bool StructuralEquivalenceContext::CheckKindSpecificEquivalence(
Decl *D1, Decl *D2) {
diff --git a/clang/lib/AST/DeclFriend.cpp b/clang/lib/AST/DeclFriend.cpp
index aea0600441d25..6bfc2eb62b284 100644
--- a/clang/lib/AST/DeclFriend.cpp
+++ b/clang/lib/AST/DeclFriend.cpp
@@ -13,9 +13,11 @@
#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>
@@ -23,9 +25,16 @@ 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) ||
@@ -37,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 {
@@ -60,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 71546c5b43070..95591d3a09431 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);
@@ -889,17 +888,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);
}
@@ -908,24 +914,6 @@ void DeclPrinter::VisitFriendDecl(FriendDecl *D) {
Out << "...";
}
-void DeclPrinter::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
- for (TemplateParameterList *TPL : D->getFriendTypeTemplateParameterLists())
- printTemplateParameters(TPL);
-
- TemplateName TN = D->getFriendTemplateName();
- if (TN.isNull()) {
- VisitFriendDecl(D);
- } else {
- Out << "friend ";
- 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 124ebcc50223b..275fe364e306d 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -1236,50 +1236,21 @@ void FriendTemplateDecl::anchor() {}
FriendTemplateDecl *
FriendTemplateDecl::Create(ASTContext &Context, DeclContext *DC,
- SourceLocation Loc, FriendUnion Friend,
- SourceLocation FriendLoc,
- ArrayRef<TemplateParameterList *> FriendTypeTPLists,
- SourceLocation EllipsisLoc) {
- std::size_t Extra =
- FriendTemplateDecl::additionalSizeToAlloc<TemplateParameterList *>(
- FriendTypeTPLists.size());
- auto *FTD = new (Context, DC, Extra) FriendTemplateDecl(
- DC, Loc, Friend, FriendLoc, EllipsisLoc, FriendTypeTPLists);
- cast<CXXRecordDecl>(DC)->pushFriendDecl(FTD);
- return FTD;
-}
-
-FriendTemplateDecl *
-FriendTemplateDecl::Create(ASTContext &Context, DeclContext *DC,
- SourceLocation Loc, TemplateName Template,
- SourceLocation FriendLoc,
- ArrayRef<TemplateParameterList *> FriendTypeTPLists,
- SourceLocation EllipsisLoc) {
- std::size_t Extra =
- FriendTemplateDecl::additionalSizeToAlloc<TemplateParameterList *>(
- FriendTypeTPLists.size());
- auto *FTD = new (Context, DC, Extra)
- FriendTemplateDecl(DC, Loc, FriendUnion(), FriendLoc, EllipsisLoc,
- FriendTypeTPLists, 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 NumFriendTypeTPLists) {
- std::size_t Extra =
- FriendTemplateDecl::additionalSizeToAlloc<TemplateParameterList *>(
- NumFriendTypeTPLists);
- return new (C, ID, Extra)
- FriendTemplateDecl(EmptyShell(), NumFriendTypeTPLists);
-}
-
-SourceRange FriendTemplateDecl::getSourceRange() const {
- SourceLocation Begin =
- getFriendTypeTemplateParameterLists().front()->getTemplateLoc();
- SourceLocation End = 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/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index b85204083cca9..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");
@@ -475,19 +473,6 @@ class ODRDeclVisitor : public ConstDeclVisitor<ODRDeclVisitor> {
Hash.AddBoolean(D->isPackExpansion());
}
- void VisitFriendTemplateDecl(const FriendTemplateDecl *D) {
- for (TemplateParameterList *TPL : D->getFriendTypeTemplateParameterLists())
- Hash.AddTemplateParameterList(TPL);
-
- TemplateName TN = D->getFriendTemplateName();
- Hash.AddBoolean(TN.isNull());
- if (TN.isNull()) {
- VisitFriendDecl(D);
- } else {
- Hash.AddTemplateName(TN);
- }
- }
-
void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
// Only care about default arguments as part of the definition.
const bool hasDefaultArgument =
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index ed3ff4bf277bc..78fbc9e31842d 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1163,9 +1163,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);
@@ -1174,7 +1173,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 582f2f779d761..17415b4185eff 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -19,11 +19,8 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Sema/DelayedDiagnostic.h"
-#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Template.h"
-#include "clang/Sema/TemplateDeduction.h"
using namespace clang;
using namespace sema;
@@ -277,243 +274,6 @@ struct AccessTarget : public AccessedEntity {
}
-static void AddFriendTemplateDeductionCandidate(
- Sema &S, TemplateDecl *TD, Decl *Declaration, TemplateDeductionInfo &Info,
- TemplateDeductionResult Result, TemplateSpecCandidateSet *FailedTSC) {
- if (!FailedTSC)
- return;
-
- for (TemplateSpecCandidate &Candidate : *FailedTSC) {
- if (!Candidate.Specialization)
- continue;
-
- if (declaresSameEntity(Candidate.Specialization, Declaration))
- return;
- }
-
- FailedTSC->addCandidate().set(
- DeclAccessPair::make(TD, AS_public), Declaration,
- MakeDeductionFailureInfo(S.Context, Result, Info));
-}
-
-static bool
-AreTemplateArgumentsStructurallyEqual(ArrayRef<TemplateArgument> LHS,
- ArrayRef<TemplateArgument> RHS) {
- return llvm::equal(
- LHS, RHS, [](const TemplateArgument &LHS, const TemplateArgument &RHS) {
- return LHS.structurallyEquals(RHS);
- });
-}
-
-static bool DeduceTemplateArguments(Sema &S, TemplateParameterList *TPL,
- TemplateDecl *TD,
- ArrayRef<TemplateArgument> PatternArgs,
- ArrayRef<TemplateArgument> Args,
- TemplateDeductionInfo &Info,
- TemplateSpecCandidateSet *FailedTSC,
- bool CopyDeducedArgs) {
- EnterExpressionEvaluationContext Unevaluated(
- S, Sema::ExpressionEvaluationContext::Unevaluated);
- Sema::SFINAETrap Trap(S, Info);
- LocalInstantiationScope InstantiationScope(S);
- SmallVector<DeducedTemplateArgument, 4> Deduced(TPL->size());
- TemplateDeductionResult DeductionResult =
- S.DeduceTemplateArguments(TPL, PatternArgs, Args, Info, Deduced,
- /*NumberOfArgumentsMustMatch=*/false);
- if (DeductionResult != TemplateDeductionResult::Success) {
- AddFriendTemplateDeductionCandidate(S, TD, TD->getTemplatedDecl(), Info,
- DeductionResult, FailedTSC);
- return false;
- }
-
- SmallVector<TemplateArgument, 4> InstArgs(Deduced.begin(), Deduced.end());
- Sema::InstantiatingTemplate Inst(S, Info.getLocation(), TD, InstArgs);
- if (Inst.isInvalid()) {
- AddFriendTemplateDeductionCandidate(
- S, TD, TD->getTemplatedDecl(), Info,
- TemplateDeductionResult::InstantiationDepth, FailedTSC);
- return false;
- }
-
- TemplateDeductionResult Result;
- S.runWithSufficientStackSpace(Info.getLocation(), [&] {
- Result = S.FinishTemplateArgumentDeduction(
- TD, TPL, PatternArgs, Args, Deduced, Info,
- /*CopyDeducedArgs=*/CopyDeducedArgs);
- });
-
- if (Result != TemplateDeductionResult::Success || Trap.hasErrorOccurred()) {
- TemplateDeductionResult Failure =
- Result != TemplateDeductionResult::Success
- ? Result
- : TemplateDeductionResult::SubstitutionFailure;
- AddFriendTemplateDeductionCandidate(S, TD, TD->getTemplatedDecl(), Info,
- Failure, FailedTSC);
- return false;
- }
-
- return true;
-}
-
-static bool
-DeduceTemplateArguments(Sema &S, TemplateParameterList *TPL, TemplateDecl *TD,
- ArrayRef<TemplateArgument> PatternArgs,
- ArrayRef<TemplateArgument> Args, SourceLocation Loc,
- TemplateSpecCandidateSet *FailedTSC,
- SmallVectorImpl<TemplateArgument> &DeducedArgs) {
- if (AreTemplateArgumentsStructurallyEqual(PatternArgs, Args)) {
- DeducedArgs.assign(Args.begin(), Args.end());
- return true;
- }
-
- TemplateDeductionInfo Info(FailedTSC ? FailedTSC->getLocation() : Loc);
- if (!DeduceTemplateArguments(S, TPL, TD, PatternArgs, Args, Info, FailedTSC,
- /*CopyDeducedArgs=*/true))
- return false;
-
- TemplateArgumentList *CanonicalDeducedArgs = Info.takeCanonical();
- DeducedArgs.assign(CanonicalDeducedArgs->asArray().begin(),
- CanonicalDeducedArgs->asArray().end());
-
- return true;
-}
-
-static bool CanDeduceTemplateArguments(Sema &S, TemplateParameterList *TPL,
- TemplateDecl *TD,
- ArrayRef<TemplateArgument> PatternArgs,
- ArrayRef<TemplateArgument> Args,
- SourceLocation Loc,
- TemplateSpecCandidateSet *FailedTSC) {
- if (AreTemplateArgumentsStructurallyEqual(PatternArgs, Args))
- return true;
-
- TemplateDeductionInfo Info(FailedTSC ? FailedTSC->getLocation() : Loc);
- return DeduceTemplateArguments(S, TPL, TD, PatternArgs, Args, Info, FailedTSC,
- /*CopyDeducedArgs=*/false);
-}
-
-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)
- return nullptr;
-
- QualType Ty(NNS.getAsType(), 0);
- if (Ty.isNull())
- return nullptr;
-
- 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 bool DeduceFriendContextTemplateArguments(
- Sema &S, DeclContext *DC, ClassTemplateDecl *FriendCTD,
- ArrayRef<TemplateArgument> FriendArgs, TemplateParameterList *FriendTPL,
- SourceLocation Loc, TemplateSpecCandidateSet *FailedTSC,
- SmallVectorImpl<TemplateArgument> &DeducedArgs) {
- const auto *RD = dyn_cast<CXXRecordDecl>(DC);
- if (!RD)
- return false;
-
- ClassTemplateDecl *ContextCTD = RD->getDescribedClassTemplate();
- ArrayRef<TemplateArgument> ContextArgs;
- if (ContextCTD) {
- ContextArgs = ContextCTD->getInjectedTemplateArgs(S.Context);
- } else {
- const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD);
- if (!CTSD)
- return false;
- ContextCTD = CTSD->getSpecializedTemplate();
- ContextArgs = CTSD->getTemplateArgs().asArray();
- }
-
- if (!declaresSameEntity(ContextCTD, FriendCTD))
- return false;
-
- return DeduceTemplateArguments(S, FriendTPL, FriendCTD, FriendArgs,
- ContextArgs, Loc, FailedTSC, DeducedArgs);
-}
-
-static bool MatchesFriendContext(Sema &S, DeclContext *DC,
- ClassTemplateDecl *FriendCTD,
- ArrayRef<TemplateArgument> FriendArgs,
- TemplateParameterList *FriendTPL,
- SourceLocation Loc,
- TemplateSpecCandidateSet *FailedTSC) {
- SmallVector<TemplateArgument, 4> DeducedArgs;
- return DeduceFriendContextTemplateArguments(
- S, DC, FriendCTD, FriendArgs, FriendTPL, Loc, FailedTSC, DeducedArgs);
-}
-
-static bool MatchesFriendContext(Sema &S, DeclContext *DC,
- ClassTemplateDecl *FriendCTD,
- DeclContext *FriendDC,
- ArrayRef<TemplateArgument> FriendArgs,
- TemplateParameterList *FriendTPL,
- SourceLocation Loc,
- TemplateSpecCandidateSet *FailedTSC) {
- auto GetClassTemplateContext =
- [](const DeclContext *DC,
- ClassTemplateDecl *Template) -> const CXXRecordDecl * {
- const auto *RD = dyn_cast<CXXRecordDecl>(DC);
- if (RD) {
- ClassTemplateDecl *CTD = RD->getDescribedClassTemplate();
- if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- CTD = CTSD->getSpecializedTemplate();
-
- if (declaresSameEntity(CTD, Template))
- return RD;
- }
- return nullptr;
- };
-
- if (const auto *FriendRecord = dyn_cast<CXXRecordDecl>(FriendDC)) {
- const CXXRecordDecl *FriendContext =
- GetClassTemplateContext(FriendRecord->getDeclContext(), FriendCTD);
- const CXXRecordDecl *Context = GetClassTemplateContext(DC, FriendCTD);
- if (declaresSameEntity(FriendContext, Context))
- return true;
- }
-
- return MatchesFriendContext(S, DC, FriendCTD, FriendArgs, FriendTPL, Loc,
- FailedTSC);
-}
-
/// Checks whether one class might instantiate to the other.
static bool MightInstantiateTo(const CXXRecordDecl *From,
const CXXRecordDecl *To) {
@@ -523,12 +283,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;
@@ -586,7 +342,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;
@@ -605,7 +363,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;
@@ -616,66 +374,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());
}
@@ -736,7 +477,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.
@@ -750,7 +491,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.
@@ -772,7 +514,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;
}
@@ -791,330 +533,63 @@ 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;
+ FTD = FTD->getCanonicalDecl();
+
if (Friend == FTD)
return AR_accessible;
- if (EC.isDependent() && MightInstantiateTo(S.Context, FTD, Friend))
+ if (EC.isDependent() && MightInstantiateTo(S, 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, const EffectiveContext &EC,
- FriendTemplateDecl *FriendTD,
- ClassTemplateDecl *FriendCTD,
- NestedNameSpecifier Qualifier,
- TemplateSpecCandidateSet *FailedTSC) {
- AccessResult OnFailure = AR_inaccessible;
- const auto *FriendTST =
- GetQualifierClassTemplateSpecializationType(S.Context, Qualifier);
- if (!FriendTST)
- return MatchesFriend(S, EC, FriendCTD);
-
- auto *FriendContextCTD = dyn_cast<ClassTemplateDecl>(
- FriendTST->getTemplateName().getAsTemplateDecl());
- if (!FriendContextCTD)
- return OnFailure;
-
- ArrayRef<TemplateParameterList *> FriendTPLists =
- FriendTD->getFriendTypeTemplateParameterLists();
- if (FriendTPLists.empty())
- return OnFailure;
-
- TemplateParameterList *FriendTPL = FriendTPLists.front();
- if (!FriendTPL)
- return OnFailure;
-
- ArrayRef<TemplateArgument> FriendArgs = FriendTST->template_arguments();
- for (CXXRecordDecl *RD : EC.Records) {
- ClassTemplateDecl *ContextCTD = nullptr;
- if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- ContextCTD = CTSD->getSpecializedTemplate();
- else
- ContextCTD = RD->getDescribedClassTemplate();
-
- if (!ContextCTD)
- continue;
-
- if (!MightInstantiateTo(ContextCTD->getTemplatedDecl(),
- FriendCTD->getTemplatedDecl()))
- continue;
-
- if (MatchesFriendContext(S, RD->getDeclContext(), FriendContextCTD,
- FriendTD->getDeclContext(), FriendArgs, FriendTPL,
- FriendTD->getLocation(), FailedTSC))
- return AR_accessible;
- }
-
- return OnFailure;
-}
-
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- FriendTemplateDecl *FriendTD,
- TemplateName Template,
- ClassTemplateDecl *FriendCTD,
- TemplateSpecCandidateSet *FailedTSC) {
- NestedNameSpecifier Qualifier = Template.getQualifier();
- if (Template.getAsUsingShadowDecl())
- Qualifier = FriendCTD->getTemplatedDecl()->getQualifier();
- return MatchesFriend(S, EC, FriendTD, FriendCTD, Qualifier, FailedTSC);
-}
-
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- FriendTemplateDecl *FriendTD,
- ClassTemplateDecl *FriendCTD,
- TemplateSpecCandidateSet *FailedTSC) {
- return MatchesFriend(S, EC, FriendTD, FriendCTD,
- FriendCTD->getTemplatedDecl()->getQualifier(),
- FailedTSC);
-}
-
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- FriendTemplateDecl *FriendTD,
- FunctionTemplateDecl *FriendFTD,
- TemplateSpecCandidateSet *FailedTSC) {
- AccessResult OnFailure = AR_inaccessible;
- const auto *FriendTST = GetQualifierClassTemplateSpecializationType(
- S.Context, FriendFTD->getTemplatedDecl()->getQualifier());
- if (!FriendTST)
- return OnFailure;
-
- auto *FriendCTD = dyn_cast<ClassTemplateDecl>(
- FriendTST->getTemplateName().getAsTemplateDecl());
- if (!FriendCTD)
- return OnFailure;
-
- ArrayRef<TemplateParameterList *> FriendTPLists =
- FriendTD->getFriendTypeTemplateParameterLists();
- if (FriendTPLists.empty())
- return OnFailure;
-
- TemplateParameterList *FriendTPL = FriendTPLists.front();
- if (!FriendTPL)
- return OnFailure;
-
- ArrayRef<TemplateArgument> FriendArgs = FriendTST->template_arguments();
- SourceLocation FriendLoc = FriendTD->getLocation();
-
- for (FunctionDecl *FD : EC.Functions) {
- if (!MatchesFriendContext(S, FD->getDeclContext(), FriendCTD, FriendArgs,
- FriendTPL, FriendLoc, FailedTSC))
- continue;
-
- FunctionTemplateDecl *ContextFTD = TryGetFunctionTemplateDecl(FD);
- if (ContextFTD && MightInstantiateTo(S.Context, FriendFTD, ContextFTD))
- return AR_accessible;
- }
-
- return OnFailure;
-}
-
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- FriendTemplateDecl *FriendTD,
- FunctionDecl *FriendFD,
- TemplateSpecCandidateSet *FailedTSC) {
- AccessResult OnFailure = AR_inaccessible;
- const auto *FriendTST = GetQualifierClassTemplateSpecializationType(
- S.Context, FriendFD->getQualifier());
- if (!FriendTST)
- return OnFailure;
-
- auto *FriendCTD = dyn_cast<ClassTemplateDecl>(
- FriendTST->getTemplateName().getAsTemplateDecl());
- if (!FriendCTD)
- return OnFailure;
-
- ArrayRef<TemplateParameterList *> FriendTPLists =
- FriendTD->getFriendTypeTemplateParameterLists();
- if (FriendTPLists.empty())
- return OnFailure;
-
- TemplateParameterList *FriendTPL = FriendTPLists.front();
- if (!FriendTPL)
- return OnFailure;
-
- ArrayRef<TemplateArgument> FriendArgs = FriendTST->template_arguments();
- SourceLocation FriendLoc = FriendTD->getLocation();
-
- for (FunctionDecl *FD : EC.Functions) {
- if (!MightInstantiateTo(S.Context, FD->getDeclName(),
- FriendFD->getDeclName()))
- continue;
-
- SmallVector<TemplateArgument, 4> DeducedArgs;
- if (!DeduceFriendContextTemplateArguments(
- S, FD->getDeclContext(), FriendCTD, FriendArgs, FriendTPL,
- FriendLoc, FailedTSC, DeducedArgs))
- continue;
-
- CanQual<FunctionProtoType> ContextProto =
- GetCanonicalFunctionProto(S.Context, FD);
- Sema::InstantiatingTemplate Inst(S, FriendFD->getLocation(), FriendCTD,
- DeducedArgs);
- if (Inst.isInvalid())
- continue;
-
- TemplateDeductionInfo Info(FriendFD->getLocation());
- Sema::SFINAETrap Trap(S, Info);
- MultiLevelTemplateArgumentList Args(FriendCTD, DeducedArgs, /*Final=*/true);
- QualType FriendType =
- S.SubstType(FriendFD->getType(), Args, FriendFD->getLocation(),
- FriendFD->getDeclName());
- if (FriendType.isNull() || Trap.hasErrorOccurred())
- continue;
-
- CanQual<FunctionProtoType> FriendProto =
- GetCanonicalFunctionProto(S.Context, FriendType);
- if (MightInstantiateTo(ContextProto, FriendProto))
- return AR_accessible;
- }
-
- return OnFailure;
-}
-
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- FriendTemplateDecl *FTD, NamedDecl *ND,
- TemplateSpecCandidateSet *FailedTSC) {
- TemplateName Template = FTD->getFriendTemplateName();
- if (auto *CTD =
- dyn_cast_if_present<ClassTemplateDecl>(Template.getAsTemplateDecl()))
- return MatchesFriend(S, EC, FTD, Template, CTD, FailedTSC);
-
- if (auto *CTD = dyn_cast<ClassTemplateDecl>(ND))
- return MatchesFriend(S, EC, FTD, CTD, FailedTSC);
-
- if (auto *TD = dyn_cast<FunctionTemplateDecl>(ND))
- return MatchesFriend(S, EC, FTD, TD, FailedTSC);
-
- if (auto *FD = dyn_cast<FunctionDecl>(ND))
- return MatchesFriend(S, EC, FTD, FD, FailedTSC);
-
- return MatchesFriend(S, EC, ND);
-}
-
-static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
- FriendTemplateDecl *FTD, TypeSourceInfo *TSI,
- TemplateSpecCandidateSet *FailedTSC) {
- QualType TypeAsWritten = TSI->getType();
- if (!TypeAsWritten->isDependentType())
- return MatchesFriend(S, EC, S.Context.getCanonicalType(TypeAsWritten));
-
- AccessResult OnFailure = EC.isDependent() ? AR_dependent : AR_inaccessible;
- const auto *DNT = TypeAsWritten->getAs<DependentNameType>();
- if (!DNT)
- return OnFailure;
-
- NestedNameSpecifier NNS = DNT->getQualifier();
- if (!NNS)
- return OnFailure;
-
- const auto *TST = GetQualifierClassTemplateSpecializationType(S.Context, NNS);
- if (!TST)
- return OnFailure;
-
- auto *CTD =
- dyn_cast<ClassTemplateDecl>(TST->getTemplateName().getAsTemplateDecl());
- if (!CTD)
- return OnFailure;
-
- ArrayRef<TemplateParameterList *> FriendTPLists =
- FTD->getFriendTypeTemplateParameterLists();
- if (FriendTPLists.empty())
- return OnFailure;
-
- TemplateParameterList *TPL = FriendTPLists.front();
- if (!TPL)
- return OnFailure;
-
- for (CXXRecordDecl *RD : EC.Records) {
- if (RD->getDeclName() != DNT->getIdentifier())
- continue;
-
- const auto *CTSD =
- dyn_cast<ClassTemplateSpecializationDecl>(RD->getDeclContext());
- if (!CTSD)
- continue;
-
- if (!declaresSameEntity(CTSD->getSpecializedTemplate(), CTD))
- continue;
-
- if (CanDeduceTemplateArguments(S, TPL, CTD, TST->template_arguments(),
- CTSD->getTemplateArgs().asArray(),
- FTD->getLocation(), FailedTSC))
- return AR_accessible;
- }
-
- return OnFailure;
-}
-
/// Determines whether the given friend declaration matches anything
/// in the effective context.
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 (NamedDecl *ND = FTD->getFriendDecl())
- return MatchesFriend(S, EC, FTD, ND, FailedTSC);
+ if (isa<ClassTemplateDecl>(Friend))
+ return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend));
- if (TypeSourceInfo *TSI = FTD->getFriendType())
- return MatchesFriend(S, EC, FTD, TSI, FailedTSC);
+ if (isa<FunctionTemplateDecl>(Friend))
+ return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend));
- return AR_inaccessible;
+ if (isa<CXXRecordDecl>(Friend))
+ return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend));
+
+ 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;
@@ -1138,7 +613,6 @@ namespace {
struct ProtectedFriendContext {
Sema &S;
const EffectiveContext &EC;
- TemplateSpecCandidateSet *FailedTSC;
const CXXRecordDecl *NamingClass;
bool CheckDependent;
bool EverDependent;
@@ -1148,19 +622,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;
@@ -1247,9 +720,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);
@@ -1257,20 +730,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");
@@ -1390,8 +862,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;
@@ -1399,7 +870,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;
@@ -1512,8 +983,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;
@@ -1709,8 +1179,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:
@@ -1753,8 +1222,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;
@@ -1858,9 +1326,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();
@@ -1872,8 +1340,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
@@ -1902,7 +1369,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
@@ -1954,30 +1421,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;
@@ -1987,20 +1449,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.
@@ -2485,8 +1933,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/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 407dacefe76a6..65b46562b166e 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18083,31 +18083,6 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
return Decl;
}
-bool Sema::CheckDependentFriend(SourceLocation Loc, NestedNameSpecifier NNS,
- TemplateParameterList *FPL) {
- if (!NNS.isDependent() || !FPL || FPL->size() == 0)
- return false;
-
- assert(NNS.getKind() == NestedNameSpecifier::Kind::Type &&
- "dependent nested-name-specifier must be a type");
- QualType T(NNS.getCanonical().getAsType(), 0);
-
- if (const auto *PIT = dyn_cast<PackIndexingType>(T))
- T = PIT->getPattern();
-
- if (const auto *TST = dyn_cast<TemplateSpecializationType>(T)) {
- if (isa_and_nonnull<ClassTemplateDecl>(
- TST->getTemplateName().getAsTemplateDecl()))
- return false;
- }
-
- if (isa<InjectedClassNameType>(T))
- return false;
-
- Diag(Loc, diag::err_dependent_friend_not_member);
- return true;
-}
-
DeclResult Sema::ActOnTemplatedFriendTag(
Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc,
CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
@@ -18123,17 +18098,16 @@ DeclResult Sema::ActOnTemplatedFriendTag(
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)
@@ -18178,8 +18152,9 @@ DeclResult Sema::ActOnTemplatedFriendTag(
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;
@@ -18205,35 +18180,25 @@ DeclResult Sema::ActOnTemplatedFriendTag(
}
}
- NestedNameSpecifier NNS = SS.getScopeRep();
- if (EllipsisLoc.isInvalid() &&
- CheckDependentFriend(TagLoc, NNS, TempParamLists.front()))
- return true;
-
+ // 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, NNS, Name);
+ 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;
- if (TempParamLists.empty())
- Friend = FriendDecl::Create(Context, CurContext, NameLoc, TSI, FriendLoc,
- EllipsisLoc);
- else {
- if (CheckTemplateDeclScope(S, TempParamLists.back()))
- return true;
-
- Friend = FriendTemplateDecl::Create(Context, CurContext, NameLoc, TSI,
- FriendLoc, TempParamLists, EllipsisLoc);
- }
-
+ FriendDecl *Friend =
+ FriendDecl::Create(Context, CurContext, NameLoc, TSI, FriendLoc,
+ EllipsisLoc, TempParamLists);
Friend->setAccess(AS_public);
+ Friend->setUnsupportedFriend(true);
CurContext->addDecl(Friend);
-
return Friend;
}
@@ -18334,14 +18299,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);
@@ -18418,7 +18380,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();
}
}
@@ -18539,11 +18501,6 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?");
}
- if (TemplateParams.size() && SS.isValid() &&
- CheckDependentFriend(NameInfo.getLoc(), SS.getScopeRep(),
- TemplateParams.front()))
- return nullptr;
-
if (!DC->isRecord()) {
int DiagArg = -1;
switch (D.getName().getKind()) {
@@ -18612,79 +18569,81 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
PushOnScopeChains(ND, EnclosingScope, /*AddToContext=*/ false);
}
- warnOnReservedIdentifier(ND);
-
- if (ND->isInvalidDecl())
- return ND;
+ FriendDecl *FrD = FriendDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(), ND,
+ DS.getFriendSpecLoc());
+ FrD->setAccess(AS_public);
+ CurContext->addDecl(FrD);
- if (DC->isRecord())
- CheckFriendAccess(ND);
+ if (ND->isInvalidDecl()) {
+ FrD->setInvalidDecl();
+ } else {
+ if (DC->isRecord()) CheckFriendAccess(ND);
- 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()) {
- 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);
- }
+ 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);
+ }
+ }
- ArrayRef<TemplateParameterList *> TPL = FD->getTemplateParameterLists();
- FriendDecl *Friend;
- if (TPL.size() > 0 && SS.isValid()) {
- if (CheckTemplateDeclScope(S, TPL.back()))
- return nullptr;
+ // 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);
+ }
- Friend =
- FriendTemplateDecl::Create(Context, CurContext, D.getIdentifierLoc(),
- ND, DS.getFriendSpecLoc(), TPL);
- } else {
- Friend = FriendDecl::Create(Context, CurContext, D.getIdentifierLoc(), ND,
- DS.getFriendSpecLoc());
+ // 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);
+ }
}
- Friend->setAccess(AS_public);
- CurContext->addDecl(Friend);
+ warnOnReservedIdentifier(ND);
return ND;
}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 19141890ca230..c8b05a9f94bd0 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12394,9 +12394,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*>()) ||
@@ -12643,10 +12642,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;
}
@@ -12662,9 +12658,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;
}
@@ -13615,12 +13609,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() {
@@ -13672,7 +13664,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 b06bf2d25ad6a..ad0e653e254dd 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1958,9 +1958,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))
@@ -11402,7 +11407,6 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
LookupQualifiedName(Result, Ctx, SS);
else
LookupName(Result, CurScope);
-
unsigned DiagID = 0;
Decl *Referenced = nullptr;
switch (Result.getResultKind()) {
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index adabbe69903db..d93b528facbcc 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -4112,16 +4112,6 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
return TemplateDeductionResult::Success;
}
-TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
- TemplateDecl *TD, TemplateParameterList *TPL,
- ArrayRef<TemplateArgument> PatternArgs, ArrayRef<TemplateArgument> Args,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- sema::TemplateDeductionInfo &Info, bool CopyDeducedArgs) {
- return ::FinishTemplateArgumentDeduction(
- *this, TD, TPL, TD, /*PartialOrdering=*/false, PatternArgs, Args, Deduced,
- Info, CopyDeducedArgs);
-}
-
/// 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,
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 8311ed5349639..c56203f10ac3c 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1989,69 +1989,68 @@ Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
return IndirectField;
}
-template <typename FriendTy>
-bool TemplateDeclInstantiator::InstantiateFriendPackExpansion(
- FriendTy *D, TypeSourceInfo *TSI, ArrayRef<TemplateParameterList *> TPL) {
- 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;
+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 {
+ 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;
- for (unsigned I = 0; I != *NumExpansions; I++) {
- Sema::ArgPackSubstIndexRAII SubstIndex(SemaRef, I);
- SmallVector<TemplateParameterList *, 1> InstTPL;
- if (SubstTemplateParameterLists(TPL, InstTPL))
- 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);
+ }
- TypeSourceInfo *InstTy = SemaRef.SubstType(
- TSI, TemplateArgs, D->getEllipsisLoc(), DeclarationName());
- if (!InstTy)
- return true;
+ // Just drop this node; we have no use for it anymore.
+ return nullptr;
+ }
+ }
- FriendDecl *FD;
- if (isa<FriendTemplateDecl>(D))
- FD = FriendTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- InstTy, D->getFriendLoc(), InstTPL);
- else {
- assert(InstTPL.empty() && "unexpected template parameter lists");
- FD = FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), InstTy,
- D->getFriendLoc());
+ InstTy = SemaRef.SubstType(Ty, TemplateArgs, D->getLocation(),
+ DeclarationName());
}
-
- FD->setAccess(AS_public);
- Owner->addDecl(FD);
- }
-
- return true;
-}
-
-Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
- if (TypeSourceInfo *Ty = D->getFriendType()) {
- if (D->isPackExpansion() && InstantiateFriendPackExpansion(D, Ty))
- return nullptr;
-
- TypeSourceInfo *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;
}
@@ -2070,6 +2069,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;
}
@@ -4711,75 +4711,12 @@ Decl *TemplateDeclInstantiator::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D)
}
Decl *TemplateDeclInstantiator::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
- ArrayRef<TemplateParameterList *> TPLists =
- D->getFriendTypeTemplateParameterLists();
-
- Decl *FTD = nullptr;
- if (TypeSourceInfo *FT = D->getFriendType()) {
- if (D->isPackExpansion() && InstantiateFriendPackExpansion(D, FT, TPLists))
- return nullptr;
-
- SmallVector<TemplateParameterList *, 1> TPL;
- if (SubstTemplateParameterLists(TPLists, TPL))
- return nullptr;
-
- TemplateName Template;
- if (auto DNT = FT->getTypeLoc().getAs<DependentNameTypeLoc>()) {
- NestedNameSpecifierLoc QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(
- DNT.getQualifierLoc(), TemplateArgs);
- if (QualifierLoc) {
- CXXScopeSpec SS;
- SS.Adopt(QualifierLoc);
-
- DeclContext *DC =
- SemaRef.computeDeclContext(SS, /*EnteringContext=*/true);
- if (DC && !DC->isDependentContext() &&
- SemaRef.RequireCompleteDeclContext(SS, DC))
- DC = nullptr;
- if (DC) {
- LookupResult Result(SemaRef, DNT.getTypePtr()->getIdentifier(),
- DNT.getNameLoc(), Sema::LookupOrdinaryName,
- SemaRef.forRedeclarationInCurContext());
- SemaRef.LookupQualifiedName(Result, DC);
- if (auto *CTD = Result.getAsSingle<ClassTemplateDecl>()) {
- auto *FoundUsingShadow =
- dyn_cast<UsingShadowDecl>(Result.getRepresentativeDecl());
- Template = FoundUsingShadow ? TemplateName(FoundUsingShadow)
- : TemplateName(CTD);
- Template = SemaRef.Context.getQualifiedTemplateName(
- QualifierLoc.getNestedNameSpecifier(),
- /*TemplateKeyword=*/false, Template);
- }
- }
- }
- }
-
- if (Template.isNull()) {
- if (TypeSourceInfo *InstTy = SemaRef.SubstType(
- FT, TemplateArgs, D->getLocation(), DeclarationName())) {
- FTD =
- FriendTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- InstTy, D->getFriendLoc(), TPL);
- }
- } else {
- FTD = FriendTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- Template, D->getFriendLoc(), TPL);
- }
- } else {
- SmallVector<TemplateParameterList *, 1> TPL;
- if (SubstTemplateParameterLists(TPLists, TPL))
- return nullptr;
-
- if (auto *InstND = cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl(
- D->getLocation(), D->getFriendDecl(), TemplateArgs)))
- FTD = FriendTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- InstND, D->getFriendLoc(), TPL);
- }
-
- if (FTD) {
- FTD->setAccess(AS_public);
- Owner->addDecl(FTD);
- }
+ // 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();
return nullptr;
}
@@ -4919,20 +4856,6 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
return InstL;
}
-bool TemplateDeclInstantiator::SubstTemplateParameterLists(
- ArrayRef<TemplateParameterList *> TPL,
- SmallVectorImpl<TemplateParameterList *> &InstTPL) {
- LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
- for (TemplateParameterList *L : TPL) {
- TemplateParameterList *InstParams = SubstTemplateParams(L);
- if (!InstParams)
- return true;
-
- InstTPL.push_back(InstParams);
- }
- return false;
-}
-
TemplateParameterList *
Sema::SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -5246,10 +5169,8 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
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 ee359268a0e3c..370a6970d531a 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2404,29 +2404,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();
- switch (Record.readInt()) {
- 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();
- break;
- }
- D->NextFriend = readDeclID().getRawValue();
+ else
+ D->Friend = readTypeSourceInfo();
D->FriendLoc = readSourceLocation();
- D->EllipsisLoc = readSourceLocation();
}
void ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
@@ -4081,11 +4078,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 3b192590fe7f8..f271769d8edf6 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1828,6 +1828,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);
@@ -1835,34 +1838,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 friend type template parameter lists here
- // so as to simplify memory allocation during deserialization.
- Record.push_back(D->NumTPLists);
VisitDecl(D);
- for (TemplateParameterList *TPL : D->getFriendTypeTemplateParameterLists())
- Record.AddTemplateParameterList(TPL);
- if (D->Template.isNull()) {
- if (D->getFriendDecl()) {
- Record.push_back(FTDK_Decl);
- Record.AddDeclRef(D->getFriendDecl());
- } else {
- Record.push_back(FTDK_Type);
- Record.AddTypeSourceInfo(D->getFriendType());
- }
- } else {
- Record.push_back(FTDK_Template);
- Record.AddTemplateName(D->Template);
- }
- Record.AddDeclRef(D->getNextFriend());
- Record.AddSourceLocation(D->FriendLoc);
- Record.AddSourceLocation(D->EllipsisLoc);
+ 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());
+ else
+ Record.AddTypeSourceInfo(D->getFriendType());
+ Record.AddSourceLocation(D->getFriendLoc());
Code = serialization::DECL_FRIEND_TEMPLATE;
}
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 3891bcc5b1975..f0424a1021abc 100644
--- a/clang/test/CXX/drs/cwg18xx.cpp
+++ b/clang/test/CXX/drs/cwg18xx.cpp
@@ -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 {{friend declaration does not name a member of a class template specialization}}
+ // 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: the primary template definition of 'D::g' is not a friend either,
-// so it should not have access to 'private_int'.
+// 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; }
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 a3ab88e82bed3..8162f9caa8f15 100644
--- a/clang/test/CXX/drs/cwg19xx.cpp
+++ b/clang/test/CXX/drs/cwg19xx.cpp
@@ -101,19 +101,19 @@ template<typename T> struct A {
};
};
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 {{friend declaration does not name a member of a class template specialization}}
+ // 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
@@ -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 {{friend declaration does not name a member of a class template specialization}}
+ // 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 e574a5f48c507..02c8f30249683 100644
--- a/clang/test/CXX/drs/cwg28xx.cpp
+++ b/clang/test/CXX/drs/cwg28xx.cpp
@@ -183,13 +183,12 @@ struct A {
friend void Ts...[0]::f();
template<typename U>
friend void Ts...[0]::g();
- // since-cxx26-error at -1 {{friend declaration does not name a member of a class template specialization}}
friend struct Ts...[0]::B;
// 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 {{friend declaration does not name a member of a class template specialization}}
+ // 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 68ac7e2346727..3ba2b372cb715 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -407,29 +407,26 @@ namespace cwg638 { // cwg638: no
};
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 {{friend declaration does not name a member of a class template specialization}}
+ // 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/p5.cpp b/clang/test/CXX/temp/temp.decls/temp.friend/p5.cpp
index ae754c5990972..a292d0de97a39 100644
--- a/clang/test/CXX/temp/temp.decls/temp.friend/p5.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.friend/p5.cpp
@@ -6,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;
};
@@ -19,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 {
@@ -35,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}}
};
}
@@ -71,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() {
@@ -86,264 +81,22 @@ namespace test3 {
namespace test4 {
template <class T> struct X {
template <class U> void operator+=(U);
-
+
template <class V>
template <class U>
- friend void X<V>::operator+=(U);
+ friend void X<V>::operator+=(U); // expected-warning {{not supported}}
};
- void test() {
+ 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 {{friend declaration does not name a member of a class template specialization}}
- };
-}
-
-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 X<int>::Y;
- // expected-error at -1 {{friend declaration does not name a member of a class template specialization}}
- };
-}
-
-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}}
- }
-}
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/Parser/cxx2c-variadic-friends.cpp b/clang/test/Parser/cxx2c-variadic-friends.cpp
index 23451e1a80a12..621ae912c1ac9 100644
--- a/clang/test/Parser/cxx2c-variadic-friends.cpp
+++ b/clang/test/Parser/cxx2c-variadic-friends.cpp
@@ -56,11 +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...;
+ 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/many-template-parameter-lists.cpp b/clang/test/SemaCXX/many-template-parameter-lists.cpp
index ad6de9ee5b25e..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>
@@ -28,12 +28,9 @@ struct X {
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); // #X-friend-operator-plus-eq
- // expected-error at -1 {{no member 'operator+=' in 'X<int>'; it has not yet been instantiated}}
- // expected-note@#X-friend-operator-plus-eq {{not-yet-instantiated member is declared here}}
+ 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;
- // expected-note at -1 {{in instantiation of template class 'X<int>' requested here}}
+ 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 747ebd3246b47..11287aa773b1b 100644
--- a/clang/test/SemaTemplate/concepts-friends.cpp
+++ b/clang/test/SemaTemplate/concepts-friends.cpp
@@ -566,61 +566,3 @@ struct Test {
};
}
-
-namespace DependentFriends {
-template <class T> concept X = requires { typename T::type; }; // #DependentFriends_X
-
-struct A {
- using type = int;
-};
-struct B {};
-
-template <class T> struct C {
- static void f()
- requires X<T>; // #DependentFriends_C_f
-};
-
-class D {
- static int n;
- template <X T> friend void C<T>::f();
-};
-
-template <class T> struct E {
- template <X U> // #DependentFriends_E_TPL
- static void f() // #DependentFriends_E_f
- requires X<T>;
-};
-
-class F {
- static int n;
- template <X T> template <X U>
- friend void E<T>::f()
- requires X<T>;
-};
-
-template <class T>
-void C<T>::f() requires X<T> {
- D::n = 0;
-}
-
-template <class T>
-template <X U>
-void E<T>::f() requires X<T> {
- F::n = 0;
-}
-
-void test() {
- C<A>::f();
- C<B>::f();
- // expected-error at -1 {{invalid reference to function 'f': constraints not satisfied}}
- // expected-note@#DependentFriends_C_f {{because 'DependentFriends::B' does not satisfy 'X'}}
- // expected-note@#DependentFriends_X {{because 'typename T::type' would be invalid: no type named 'type' in 'DependentFriends::B'}}
-
- E<A>::f<A>();
- E<A>::f<B>();
- // expected-error at -1 {{no matching function for call to 'f'}}
- // expected-note@#DependentFriends_E_f {{candidate template ignored: constraints not satisfied}}
- // expected-note@#DependentFriends_E_TPL {{because 'DependentFriends::B' does not satisfy 'X'}}
- // expected-note@#DependentFriends_X {{because 'typename T::type' would be invalid: no type named 'type' in 'DependentFriends::B'}}
-}
-}
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/friend-template.cpp b/clang/test/SemaTemplate/friend-template.cpp
index 4a8f23a56dd22..2b5a226c3b33c 100644
--- a/clang/test/SemaTemplate/friend-template.cpp
+++ b/clang/test/SemaTemplate/friend-template.cpp
@@ -235,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 {
@@ -337,28 +338,3 @@ class Foo {
bool aux;
};
}
-
-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}}
-}
-}
More information about the cfe-commits
mailing list