forked from OSchip/llvm-project
In MSVC compatibility mode, friend function declarations behave as function declarations
Before C++20, MSVC treated any friend function declaration as a function declaration, so the following code would compile despite funGlob being declared after its first call: ``` class Glob { public: friend void funGlob(); void test() { funGlob(); } }; void funGlob() {} ``` This proposed patch mimics the MSVC behavior when in MSVC compatibility mode Reviewed By: rnk Differential Revision: https://reviews.llvm.org/D124613
This commit is contained in:
parent
bc8e601257
commit
ad47114ad8
|
@ -9632,11 +9632,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
}
|
|
@ -2658,7 +2658,10 @@ TEST_P(ImportFriendFunctions, Lookup) {
|
|||
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 @@ TEST_P(ImportFriendFunctions, LookupWithProtoAfter) {
|
|||
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 @@ TEST_P(ImportFriendFunctions, ImportFriendChangesLookup) {
|
|||
|
||||
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());
|
||||
|
|
Loading…
Reference in New Issue