Skip to content

Commit 4ac1416

Browse files
[C++20][Modules] NFC Reworked handling of inline for functions defined in class (llvm#109470)
Reworked handling of implicit inline marking for member and friend function defined in class. Now, we handle it in an additive manner, i.e. if such in-class functions are inline implicitly by language rules, we mark the as `setImplicitInline`, and perform no action otherwise. As we never remove inline specifier, the implementation is orthogonal to other sources of inline (like `inline`, `constexpr`, e.t.c), and we do not need to handle them specially. Also included test for `constexpr`, `consteval` and global module cases.
1 parent 1493c24 commit 4ac1416

File tree

3 files changed

+85
-16
lines changed

3 files changed

+85
-16
lines changed

clang/lib/Sema/SemaDecl.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9762,26 +9762,26 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
97629762
if (getLangOpts().CPlusPlus) {
97639763
// The rules for implicit inlines changed in C++20 for methods and friends
97649764
// with an in-class definition (when such a definition is not attached to
9765-
// the global module). User-specified 'inline' overrides this (set when
9766-
// the function decl is created above).
9765+
// the global module). This does not affect declarations that are already
9766+
// inline (whether explicitly or implicitly by being declared constexpr,
9767+
// consteval, etc).
97679768
// FIXME: We need a better way to separate C++ standard and clang modules.
97689769
bool ImplicitInlineCXX20 = !getLangOpts().CPlusPlusModules ||
9769-
NewFD->isConstexpr() || NewFD->isConsteval() ||
97709770
!NewFD->getOwningModule() ||
97719771
NewFD->isFromGlobalModule() ||
97729772
NewFD->getOwningModule()->isHeaderLikeModule();
97739773
bool isInline = D.getDeclSpec().isInlineSpecified();
97749774
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
97759775
bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
97769776
isFriend = D.getDeclSpec().isFriendSpecified();
9777-
if (isFriend && !isInline && D.isFunctionDefinition()) {
9777+
if (ImplicitInlineCXX20 && isFriend && D.isFunctionDefinition()) {
97789778
// Pre-C++20 [class.friend]p5
97799779
// A function can be defined in a friend declaration of a
97809780
// class . . . . Such a function is implicitly inline.
97819781
// Post C++20 [class.friend]p7
97829782
// Such a function is implicitly an inline function if it is attached
97839783
// to the global module.
9784-
NewFD->setImplicitlyInline(ImplicitInlineCXX20);
9784+
NewFD->setImplicitlyInline();
97859785
}
97869786

97879787
// 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,
1008310083
break;
1008410084
}
1008510085

10086-
if (isa<CXXMethodDecl>(NewFD) && DC == CurContext &&
10087-
D.isFunctionDefinition() && !isInline) {
10086+
if (ImplicitInlineCXX20 && isa<CXXMethodDecl>(NewFD) && DC == CurContext &&
10087+
D.isFunctionDefinition()) {
1008810088
// Pre C++20 [class.mfct]p2:
1008910089
// A member function may be defined (8.4) in its class definition, in
1009010090
// which case it is an inline member function (7.1.2)
1009110091
// Post C++20 [class.mfct]p1:
1009210092
// If a member function is attached to the global module and is defined
1009310093
// in its class definition, it is inline.
10094-
NewFD->setImplicitlyInline(ImplicitInlineCXX20);
10094+
NewFD->setImplicitlyInline();
1009510095
}
1009610096

1009710097
if (!isFriend && SC != SC_None) {

clang/test/CXX/class/class.friend/p7-cxx20.cpp

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,51 @@ module;
4646
export module M;
4747

4848
class Z {
49-
friend void z(){};
49+
friend void z1(){};
5050
};
51+
52+
class Inline {
53+
friend inline void z2(){};
54+
};
55+
56+
class Constexpr {
57+
friend constexpr void z3(){};
58+
};
59+
60+
class Consteval {
61+
friend consteval void z4(){};
62+
};
63+
64+
extern "C++" class GlobalModule {
65+
friend void z5(){};
66+
};
67+
5168
// CHECK-MOD: |-CXXRecordDecl {{.*}} <.{{/|\\\\?}}header.h:2:1, line:4:1> line:2:7 in M.<global> hidden class A definition
5269
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M.<global> hidden implicit class A
5370
// CHECK-MOD-NEXT: | `-FriendDecl {{.*}} <line:3:3, col:19> col:15 in M.<global>
5471
// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:19> col:15 in M.<global> hidden friend_undeclared a 'void ()' implicit-inline
5572

56-
// CHECK-MOD: `-CXXRecordDecl {{.*}} <module.cpp:6:1, line:8:1> line:6:7 in M hidden class Z{{( ReachableWhenImported)?}} definition
57-
// CHECK-MOD: |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Z{{( ReachableWhenImported)?}}
58-
// CHECK-MOD-NEXT: `-FriendDecl {{.*}} <line:7:3, col:19> col:15 in M{{( ReachableWhenImported)?}}
59-
// CHECK-MOD-NEXT: `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:19> col:15 in M hidden friend_undeclared z 'void ()'{{( ReachableWhenImported)?}}
73+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <module.cpp:6:1, line:8:1> line:6:7 in M hidden class Z{{( ReachableWhenImported)?}} definition
74+
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Z{{( ReachableWhenImported)?}}
75+
// CHECK-MOD-NEXT: | `-FriendDecl {{.*}} <line:7:3, col:20> col:15 in M{{( ReachableWhenImported)?}}
76+
// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:20> col:15 in M hidden friend_undeclared z1 'void ()'{{( ReachableWhenImported)?}}
77+
78+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <line:10:1, line:12:1> line:10:7 in M hidden class Inline{{( ReachableWhenImported)?}} definition
79+
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Inline{{( ReachableWhenImported)?}}
80+
// CHECK-MOD-NEXT: | `-FriendDecl {{.*}} <line:11:3, col:27> col:22 in M{{( ReachableWhenImported)?}}
81+
// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:27> col:22 in M hidden friend_undeclared z2 'void ()'{{( ReachableWhenImported)?}} inline
82+
83+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <line:14:1, line:16:1> line:14:7 in M hidden class Constexpr{{( ReachableWhenImported)?}} definition
84+
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Constexpr{{( ReachableWhenImported)?}}
85+
// CHECK-MOD-NEXT: | `-FriendDecl {{.*}} <line:15:3, col:30> col:25 in M{{( ReachableWhenImported)?}}
86+
// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:30> col:25 in M hidden constexpr friend_undeclared z3 'void ()'{{( ReachableWhenImported)?}} implicit-inline
87+
88+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <line:18:1, line:20:1> line:18:7 in M hidden class Consteval{{( ReachableWhenImported)?}} definition
89+
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Consteval{{( ReachableWhenImported)?}}
90+
// CHECK-MOD-NEXT: | `-FriendDecl {{.*}} <line:19:3, col:30> col:25 in M{{( ReachableWhenImported)?}}
91+
// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:30> col:25 in M hidden consteval friend_undeclared z4 'void ()'{{( ReachableWhenImported)?}} implicit-inline
92+
93+
// CHECK-MOD: `-CXXRecordDecl {{.*}} <col:14, line:24:1> line:22:20 in M.<implicit global> hidden class GlobalModule{{( ReachableWhenImported)?}} definition
94+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <col:14, col:20> col:20 in M.<implicit global> hidden implicit class GlobalModule{{( ReachableWhenImported)?}}
95+
// CHECK-MOD-NEXT: `-FriendDecl {{.*}} <line:23:3, col:20> col:15 in M.<implicit global>{{( ReachableWhenImported)?}}
96+
// CHECK-MOD-NEXT: `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:20> col:15 in M.<implicit global> hidden friend_undeclared z5 'void ()'{{( ReachableWhenImported)?}} implicit-inline

clang/test/CXX/class/class.mfct/p1-cxx20.cpp

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,42 @@ class Z {
4848
void z(){};
4949
};
5050

51+
class Inline {
52+
inline void z(){};
53+
};
54+
55+
class Constexpr {
56+
constexpr void z(){};
57+
};
58+
59+
class Consteval {
60+
consteval void z(){};
61+
};
62+
63+
extern "C++" class GlobalModule {
64+
void z(){};
65+
};
66+
5167
// CHECK-MOD: |-CXXRecordDecl {{.*}} <.{{/|\\\\?}}header.h:2:1, line:4:1> line:2:7 in M.<global> hidden class A definition
5268
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M.<global> hidden implicit class A
5369
// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} <line:3:3, col:12> col:8 in M.<global> hidden a 'void ()' implicit-inline
5470

55-
// CHECK-MOD: `-CXXRecordDecl {{.*}} <module.cpp:6:1, line:8:1> line:6:7 in M hidden class Z{{( ReachableWhenImported)?}} definition
56-
// CHECK-MOD: |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Z{{( ReachableWhenImported)?}}
57-
// CHECK-MOD-NEXT: `-CXXMethodDecl {{.*}} <line:7:3, col:12> col:8 in M hidden z 'void ()'{{( ReachableWhenImported)?}}
71+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <module.cpp:6:1, line:8:1> line:6:7 in M hidden class Z{{( ReachableWhenImported)?}} definition
72+
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Z{{( ReachableWhenImported)?}}
73+
// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} <line:7:3, col:12> col:8 in M hidden z 'void ()'{{( ReachableWhenImported)?}}
74+
75+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <line:10:1, line:12:1> line:10:7 in M hidden class Inline{{( ReachableWhenImported)?}} definition
76+
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Inline{{( ReachableWhenImported)?}}
77+
// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} <line:11:3, col:19> col:15 in M hidden z 'void ()'{{( ReachableWhenImported)?}} inline
78+
79+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <line:14:1, line:16:1> line:14:7 in M hidden class Constexpr{{( ReachableWhenImported)?}} definition
80+
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Constexpr{{( ReachableWhenImported)?}}
81+
// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} <line:15:3, col:22> col:18 in M hidden constexpr z 'void ()'{{( ReachableWhenImported)?}} implicit-inline
82+
83+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <line:18:1, line:20:1> line:18:7 in M hidden class Consteval{{( ReachableWhenImported)?}} definition
84+
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Consteval{{( ReachableWhenImported)?}}
85+
// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} <line:19:3, col:22> col:18 in M hidden consteval z 'void ()'{{( ReachableWhenImported)?}} implicit-inline
86+
87+
// CHECK-MOD: `-CXXRecordDecl {{.*}} <col:14, line:24:1> line:22:20 in M.<implicit global> hidden class GlobalModule{{( ReachableWhenImported)?}} definition
88+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <col:14, col:20> col:20 in M.<implicit global> hidden implicit class GlobalModule{{( ReachableWhenImported)?}}
89+
// CHECK-MOD-NEXT: `-CXXMethodDecl {{.*}} <line:23:3, col:12> col:8 in M.<implicit global> hidden z 'void ()'{{( ReachableWhenImported)?}} implicit-inline

0 commit comments

Comments
 (0)