Index: clang/include/clang/AST/Decl.h =================================================================== --- clang/include/clang/AST/Decl.h +++ clang/include/clang/AST/Decl.h @@ -2490,6 +2490,11 @@ AC.push_back(TRC); } + // For the purposes of mangling, determine if this is a friend function with + // constraints on it, so that we can decide to mangle this with its containing + // scope and the 'F' for itanium. + bool isConstrainedFriend() const; + void setPreviousDeclaration(FunctionDecl * PrevDecl); FunctionDecl *getCanonicalDecl() override; Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -3349,6 +3349,13 @@ return isMultiVersion() && hasAttr(); } +bool FunctionDecl::isConstrainedFriend() const { + return getFriendObjectKind() && + (getTrailingRequiresClause() || + (getDescribedFunctionTemplate() && + getDescribedFunctionTemplate()->hasAssociatedConstraints())); +} + void FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { redeclarable_base::setPreviousDecl(PrevDecl); Index: clang/lib/AST/ItaniumMangle.cpp =================================================================== --- clang/lib/AST/ItaniumMangle.cpp +++ clang/lib/AST/ItaniumMangle.cpp @@ -658,10 +658,25 @@ if (VD->isExternC()) return getASTContext().getTranslationUnitDecl(); - if (const auto *FD = dyn_cast(D)) + if (const auto *FD = dyn_cast(D)) { if (FD->isExternC()) return getASTContext().getTranslationUnitDecl(); + // If this is a friend, and has constraints, mangle it in the decl context + // of its lexical context, since in different scopes, they are considered + // different functions. See [temp.friend]p9. + if (FD->isConstrainedFriend()) + return FD->getLexicalDeclContext(); + } + + // If this is a friend, and has constraints, mangle it in the decl context + // of its lexical context, since in different scopes, they are considered + // different functions. See [temp.friend]p9. + // For template friends, we just use the templated decl version here. + if (const auto *FTD = dyn_cast(D)) + if (FTD->getTemplatedDecl()->isConstrainedFriend()) + return FTD->getLexicalDeclContext(); + return DC->getRedeclContext(); } @@ -1697,13 +1712,26 @@ Out << II->getLength() << II->getName(); } +// See if the 'F' between the prefix of a nested name or nested template is +// necessary. That is, is this a friend with a constraint. +static void mangleConstrainedFriendness(llvm::raw_ostream &Out, GlobalDecl GD) { + if (const auto *FD = dyn_cast(GD.getDecl())) + if (FD->isConstrainedFriend()) + Out << 'F'; + + if (const auto *FTD = dyn_cast(GD.getDecl())) + if (FTD->getTemplatedDecl()->isConstrainedFriend()) + Out << 'F'; +} + void CXXNameMangler::mangleNestedName(GlobalDecl GD, const DeclContext *DC, const AbiTagList *AdditionalAbiTags, bool NoFunction) { const NamedDecl *ND = cast(GD.getDecl()); // - // ::= N [] [] E + // ::= N [] [] [F} + // E // ::= N [] [] // E @@ -1724,6 +1752,7 @@ mangleTemplateArgs(asTemplateName(TD), *TemplateArgs); } else { manglePrefix(DC, NoFunction); + mangleConstrainedFriendness(Out, GD); mangleUnqualifiedName(GD, DC, AdditionalAbiTags); } @@ -2143,7 +2172,7 @@ void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD, bool NoFunction) { const TemplateDecl *ND = cast(GD.getDecl()); - // ::=