diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index de8805e15bc750..19e91a17e6344a 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9760,8 +9760,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (getLangOpts().CPlusPlus) { // The rules for implicit inlines changed in C++20 for methods and friends // with an in-class definition (when such a definition is not attached to - // the global module). User-specified 'inline' overrides this (set when - // the function decl is created above). + // the global module). This does not affect declarations, that are already + // inline, for example due declared `inline` or `consteval` // FIXME: We need a better way to separate C++ standard and clang modules. bool ImplicitInlineCXX20 = !getLangOpts().CPlusPlusModules || NewFD->isConstexpr() || NewFD->isConsteval() || @@ -9772,14 +9772,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier(); isFriend = D.getDeclSpec().isFriendSpecified(); - if (isFriend && !isInline && D.isFunctionDefinition()) { + if (ImplicitInlineCXX20 && isFriend && D.isFunctionDefinition()) { // Pre-C++20 [class.friend]p5 // A function can be defined in a friend declaration of a // class . . . . Such a function is implicitly inline. // Post C++20 [class.friend]p7 // Such a function is implicitly an inline function if it is attached // to the global module. - NewFD->setImplicitlyInline(ImplicitInlineCXX20); + NewFD->setImplicitlyInline(); } // If this is a method defined in an __interface, and is not a constructor @@ -10083,15 +10083,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, break; } - if (isa(NewFD) && DC == CurContext && - D.isFunctionDefinition() && !isInline) { + if (ImplicitInlineCXX20 && isa(NewFD) && DC == CurContext && + D.isFunctionDefinition()) { // Pre C++20 [class.mfct]p2: // A member function may be defined (8.4) in its class definition, in // which case it is an inline member function (7.1.2) // Post C++20 [class.mfct]p1: // If a member function is attached to the global module and is defined // in its class definition, it is inline. - NewFD->setImplicitlyInline(ImplicitInlineCXX20); + NewFD->setImplicitlyInline(); } if (!isFriend && SC != SC_None) { diff --git a/clang/test/CXX/class/class.friend/p7-cxx20.cpp b/clang/test/CXX/class/class.friend/p7-cxx20.cpp index 8843d55910ea2d..04fb5d3d6b03ae 100644 --- a/clang/test/CXX/class/class.friend/p7-cxx20.cpp +++ b/clang/test/CXX/class/class.friend/p7-cxx20.cpp @@ -46,14 +46,42 @@ module; export module M; class Z { - friend void z(){}; + friend void z1(){}; }; + +class Inline { + friend inline void z2(){}; +}; + +class Constexpr { + friend constexpr void z3(){}; +}; + +class Consteval { + friend consteval void z4(){}; +}; + // CHECK-MOD: |-CXXRecordDecl {{.*}} <.{{/|\\\\?}}header.h:2:1, line:4:1> line:2:7 in M. hidden class A definition // CHECK-MOD: | |-CXXRecordDecl {{.*}} col:7 in M. hidden implicit class A // CHECK-MOD-NEXT: | `-FriendDecl {{.*}} col:15 in M. // CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} col:15 in M. hidden friend_undeclared a 'void ()' implicit-inline -// CHECK-MOD: `-CXXRecordDecl {{.*}} line:6:7 in M hidden class Z{{( ReachableWhenImported)?}} definition -// CHECK-MOD: |-CXXRecordDecl {{.*}} col:7 in M hidden implicit class Z{{( ReachableWhenImported)?}} -// CHECK-MOD-NEXT: `-FriendDecl {{.*}} col:15 in M{{( ReachableWhenImported)?}} -// CHECK-MOD-NEXT: `-FunctionDecl {{.*}} parent {{.*}} col:15 in M hidden friend_undeclared z 'void ()'{{( ReachableWhenImported)?}} +// CHECK-MOD: |-CXXRecordDecl {{.*}} line:6:7 in M hidden class Z{{( ReachableWhenImported)?}} definition +// CHECK-MOD: | |-CXXRecordDecl {{.*}} col:7 in M hidden implicit class Z{{( ReachableWhenImported)?}} +// CHECK-MOD-NEXT: | `-FriendDecl {{.*}} col:15 in M{{( ReachableWhenImported)?}} +// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} col:15 in M hidden friend_undeclared z1 'void ()'{{( ReachableWhenImported)?}} + +// CHECK-MOD: |-CXXRecordDecl {{.*}} line:10:7 in M hidden class Inline{{( ReachableWhenImported)?}} definition +// CHECK-MOD: | |-CXXRecordDecl {{.*}} col:7 in M hidden implicit class Inline{{( ReachableWhenImported)?}} +// CHECK-MOD-NEXT: | `-FriendDecl {{.*}} col:22 in M{{( ReachableWhenImported)?}} +// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} col:22 in M hidden friend_undeclared z2 'void ()'{{( ReachableWhenImported)?}} inline + +// CHECK-MOD: |-CXXRecordDecl {{.*}} line:14:7 in M hidden class Constexpr{{( ReachableWhenImported)?}} definition +// CHECK-MOD: | |-CXXRecordDecl {{.*}} col:7 in M hidden implicit class Constexpr{{( ReachableWhenImported)?}} +// CHECK-MOD-NEXT: | `-FriendDecl {{.*}} col:25 in M{{( ReachableWhenImported)?}} +// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} col:25 in M hidden constexpr friend_undeclared z3 'void ()'{{( ReachableWhenImported)?}} implicit-inline + +// CHECK-MOD: `-CXXRecordDecl {{.*}} line:18:7 in M hidden class Consteval{{( ReachableWhenImported)?}} definition +// CHECK-MOD: |-CXXRecordDecl {{.*}} col:7 in M hidden implicit class Consteval{{( ReachableWhenImported)?}} +// CHECK-MOD-NEXT: `-FriendDecl {{.*}} col:25 in M{{( ReachableWhenImported)?}} +// CHECK-MOD-NEXT: `-FunctionDecl {{.*}} parent {{.*}} col:25 in M hidden consteval friend_undeclared z4 'void ()'{{( ReachableWhenImported)?}} implicit-inline \ No newline at end of file diff --git a/clang/test/CXX/class/class.mfct/p1-cxx20.cpp b/clang/test/CXX/class/class.mfct/p1-cxx20.cpp index 5b24668d7b6617..9b990e13c09791 100644 --- a/clang/test/CXX/class/class.mfct/p1-cxx20.cpp +++ b/clang/test/CXX/class/class.mfct/p1-cxx20.cpp @@ -48,10 +48,34 @@ class Z { void z(){}; }; +class Inline { + inline void z(){}; +}; + +class Constexpr { + constexpr void z(){}; +}; + +class Consteval { + consteval void z(){}; +}; + // CHECK-MOD: |-CXXRecordDecl {{.*}} <.{{/|\\\\?}}header.h:2:1, line:4:1> line:2:7 in M. hidden class A definition // CHECK-MOD: | |-CXXRecordDecl {{.*}} col:7 in M. hidden implicit class A // CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} col:8 in M. hidden a 'void ()' implicit-inline -// CHECK-MOD: `-CXXRecordDecl {{.*}} line:6:7 in M hidden class Z{{( ReachableWhenImported)?}} definition -// CHECK-MOD: |-CXXRecordDecl {{.*}} col:7 in M hidden implicit class Z{{( ReachableWhenImported)?}} -// CHECK-MOD-NEXT: `-CXXMethodDecl {{.*}} col:8 in M hidden z 'void ()'{{( ReachableWhenImported)?}} +// CHECK-MOD: |-CXXRecordDecl {{.*}} line:6:7 in M hidden class Z{{( ReachableWhenImported)?}} definition +// CHECK-MOD: | |-CXXRecordDecl {{.*}} col:7 in M hidden implicit class Z{{( ReachableWhenImported)?}} +// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} col:8 in M hidden z 'void ()'{{( ReachableWhenImported)?}} + +// CHECK-MOD: |-CXXRecordDecl {{.*}} line:10:7 in M hidden class Inline{{( ReachableWhenImported)?}} definition +// CHECK-MOD: | |-CXXRecordDecl {{.*}} col:7 in M hidden implicit class Inline{{( ReachableWhenImported)?}} +// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} col:15 in M hidden z 'void ()'{{( ReachableWhenImported)?}} inline + +// CHECK-MOD: |-CXXRecordDecl {{.*}} line:14:7 in M hidden class Constexpr{{( ReachableWhenImported)?}} definition +// CHECK-MOD: | |-CXXRecordDecl {{.*}} col:7 in M hidden implicit class Constexpr{{( ReachableWhenImported)?}} +// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} col:18 in M hidden constexpr z 'void ()'{{( ReachableWhenImported)?}} implicit-inline + +// CHECK-MOD: `-CXXRecordDecl {{.*}} line:18:7 in M hidden class Consteval{{( ReachableWhenImported)?}} definition +// CHECK-MOD: |-CXXRecordDecl {{.*}} col:7 in M hidden implicit class Consteval{{( ReachableWhenImported)?}} +// CHECK-MOD-NEXT: `-CXXMethodDecl {{.*}} col:18 in M hidden consteval z 'void ()'{{( ReachableWhenImported)?}} implicit-inline