This revision was automatically updated to reflect the committed changes. Closed by commit rGad47114ad850: In MSVC compatibility mode, friend function declarations behave as function… (authored by frederic-tingaud-sonarsource, committed by mantognini).
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D124613/new/ https://reviews.llvm.org/D124613 Files: clang/lib/Sema/SemaDecl.cpp clang/test/SemaCXX/ms-friend-function-decl.cpp clang/unittests/AST/ASTImporterTest.cpp
Index: clang/unittests/AST/ASTImporterTest.cpp =================================================================== --- clang/unittests/AST/ASTImporterTest.cpp +++ clang/unittests/AST/ASTImporterTest.cpp @@ -2658,7 +2658,10 @@ getTuDecl("struct X { friend void f(); };", Lang_CXX03, "input0.cc"); auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, FunctionPattern); ASSERT_TRUE(FromD->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend)); - ASSERT_FALSE(FromD->isInIdentifierNamespace(Decl::IDNS_Ordinary)); + // Before CXX20, MSVC treats friend function declarations as function + // declarations + ASSERT_EQ(FromTU->getLangOpts().MSVCCompat, + FromD->isInIdentifierNamespace(Decl::IDNS_Ordinary)); { auto FromName = FromD->getDeclName(); auto *Class = FirstDeclMatcher<CXXRecordDecl>().match(FromTU, ClassPattern); @@ -2702,7 +2705,10 @@ auto *FromNormal = LastDeclMatcher<FunctionDecl>().match(FromTU, FunctionPattern); ASSERT_TRUE(FromFriend->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend)); - ASSERT_FALSE(FromFriend->isInIdentifierNamespace(Decl::IDNS_Ordinary)); + // Before CXX20, MSVC treats friend function declarations as function + // declarations + ASSERT_EQ(FromTU->getLangOpts().MSVCCompat, + FromFriend->isInIdentifierNamespace(Decl::IDNS_Ordinary)); ASSERT_FALSE(FromNormal->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend)); ASSERT_TRUE(FromNormal->isInIdentifierNamespace(Decl::IDNS_Ordinary)); @@ -2793,7 +2799,10 @@ ASSERT_TRUE(FromNormalF->isInIdentifierNamespace(Decl::IDNS_Ordinary)); ASSERT_FALSE(FromNormalF->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend)); - ASSERT_FALSE(FromFriendF->isInIdentifierNamespace(Decl::IDNS_Ordinary)); + // Before CXX20, MSVC treats friend function declarations as function + // declarations + ASSERT_EQ(FromFriendTU->getLangOpts().MSVCCompat, + FromFriendF->isInIdentifierNamespace(Decl::IDNS_Ordinary)); ASSERT_TRUE(FromFriendF->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend)); auto LookupRes = FromNormalTU->noload_lookup(FromNormalName); ASSERT_TRUE(LookupRes.isSingleResult()); Index: clang/test/SemaCXX/ms-friend-function-decl.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/ms-friend-function-decl.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -std=c++03 -fms-compatibility -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++17 -fms-compatibility -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++20 -fms-compatibility -fsyntax-only -verify=modern %s +#if __cplusplus < 202002L +// expected-no-diagnostics +#endif + +namespace ns { + +class C { +public: + template <typename T> + friend void funtemp(); + + friend void fun(); + + void test() { + ::ns::fun(); // modern-error {{no member named 'fun' in namespace 'ns'}} + + // modern-error@+3 {{no member named 'funtemp' in namespace 'ns'}} + // modern-error@+2 {{expected '(' for function-style cast or type construction}} + // modern-error@+1 {{expected expression}} + ::ns::funtemp<int>(); + } +}; + +void fun() { +} + +template <typename T> +void funtemp() {} + +} // namespace ns + +class Glob { +public: + friend void funGlob(); + + void test() { + funGlob(); // modern-error {{use of undeclared identifier 'funGlob'}} + } +}; + +void funGlob() { +} Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -9632,11 +9632,15 @@ } if (isFriend) { + // In MSVC mode for older versions of the standard, friend function + // declarations behave as declarations + bool PerformFriendInjection = + getLangOpts().MSVCCompat && !getLangOpts().CPlusPlus20; if (FunctionTemplate) { - FunctionTemplate->setObjectOfFriendDecl(); + FunctionTemplate->setObjectOfFriendDecl(PerformFriendInjection); FunctionTemplate->setAccess(AS_public); } - NewFD->setObjectOfFriendDecl(); + NewFD->setObjectOfFriendDecl(PerformFriendInjection); NewFD->setAccess(AS_public); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits