Skip to content

Commit 6ff9964

Browse files
[C++20][Modules] Restore inliness of constexpr/consteval functions defined in-class
This correct issue, when the functions declared as `constexpr` are `consteval`, are not considered to be inline (`isInlined()` is false) when defined inside class attached to named module: ```c++ export module mod; struct Clazz { constexpr void f1() { } // non-inline constexpr void f2(); friend constexpr void f3() {} // non-inline }; constexpr void Clazz::f3() {} // inline ``` This conflicts with [decl.constexpr] p1: > A function or static data member declared with the constexpr or consteval specifier on its first declaration is implicitly an inline function or variable ([dcl.inline]). If any declaration of a function or function template has a constexpr or consteval specifier, then all its declarations shall contain the same specifier/) This regression was introduced by 97af17c5, where the inline of such function was accidentally removed The corresponding wording in [class.friend] and p6 [class.mfct] p1 uses "if" and not "if and only if", thus does not imply that these are only cases where such functions are inline.
1 parent a065295 commit 6ff9964

File tree

3 files changed

+67
-15
lines changed

3 files changed

+67
-15
lines changed

clang/lib/Sema/SemaDecl.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9760,8 +9760,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
97609760
if (getLangOpts().CPlusPlus) {
97619761
// The rules for implicit inlines changed in C++20 for methods and friends
97629762
// with an in-class definition (when such a definition is not attached to
9763-
// the global module). User-specified 'inline' overrides this (set when
9764-
// the function decl is created above).
9763+
// the global module). This does not affect declarations, that are already
9764+
// inline, for example due being declared `inline` or `consteval`
97659765
// FIXME: We need a better way to separate C++ standard and clang modules.
97669766
bool ImplicitInlineCXX20 = !getLangOpts().CPlusPlusModules ||
97679767
NewFD->isConstexpr() || NewFD->isConsteval() ||
@@ -9772,14 +9772,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
97729772
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
97739773
bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
97749774
isFriend = D.getDeclSpec().isFriendSpecified();
9775-
if (isFriend && !isInline && D.isFunctionDefinition()) {
9775+
if (ImplicitInlineCXX20 && isFriend && D.isFunctionDefinition()) {
97769776
// Pre-C++20 [class.friend]p5
97779777
// A function can be defined in a friend declaration of a
97789778
// class . . . . Such a function is implicitly inline.
97799779
// Post C++20 [class.friend]p7
97809780
// Such a function is implicitly an inline function if it is attached
97819781
// to the global module.
9782-
NewFD->setImplicitlyInline(ImplicitInlineCXX20);
9782+
NewFD->setImplicitlyInline();
97839783
}
97849784

97859785
// 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: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,42 @@ 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+
5164
// CHECK-MOD: |-CXXRecordDecl {{.*}} <.{{/|\\\\?}}header.h:2:1, line:4:1> line:2:7 in M.<global> hidden class A definition
5265
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M.<global> hidden implicit class A
5366
// CHECK-MOD-NEXT: | `-FriendDecl {{.*}} <line:3:3, col:19> col:15 in M.<global>
5467
// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:19> col:15 in M.<global> hidden friend_undeclared a 'void ()' implicit-inline
5568

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)?}}
69+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <module.cpp:6:1, line:8:1> line:6:7 in M hidden class Z{{( ReachableWhenImported)?}} definition
70+
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Z{{( ReachableWhenImported)?}}
71+
// CHECK-MOD-NEXT: | `-FriendDecl {{.*}} <line:7:3, col:20> col:15 in M{{( ReachableWhenImported)?}}
72+
// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:20> col:15 in M hidden friend_undeclared z1 'void ()'{{( ReachableWhenImported)?}}
73+
74+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <line:10:1, line:12:1> line:10:7 in M hidden class Inline{{( ReachableWhenImported)?}} definition
75+
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Inline{{( ReachableWhenImported)?}}
76+
// CHECK-MOD-NEXT: | `-FriendDecl {{.*}} <line:11:3, col:27> col:22 in M{{( ReachableWhenImported)?}}
77+
// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:27> col:22 in M hidden friend_undeclared z2 '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: | `-FriendDecl {{.*}} <line:15:3, col:30> col:25 in M{{( ReachableWhenImported)?}}
82+
// CHECK-MOD-NEXT: | `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:30> col:25 in M hidden constexpr friend_undeclared z3 'void ()'{{( ReachableWhenImported)?}} implicit-inline
83+
84+
// CHECK-MOD: `-CXXRecordDecl {{.*}} <line:18:1, line:20:1> line:18:7 in M hidden class Consteval{{( ReachableWhenImported)?}} definition
85+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Consteval{{( ReachableWhenImported)?}}
86+
// CHECK-MOD-NEXT: `-FriendDecl {{.*}} <line:19:3, col:30> col:25 in M{{( ReachableWhenImported)?}}
87+
// CHECK-MOD-NEXT: `-FunctionDecl {{.*}} parent {{.*}} <col:3, col:30> col:25 in M hidden consteval friend_undeclared z4 'void ()'{{( ReachableWhenImported)?}} implicit-inline

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

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,34 @@ 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+
5163
// CHECK-MOD: |-CXXRecordDecl {{.*}} <.{{/|\\\\?}}header.h:2:1, line:4:1> line:2:7 in M.<global> hidden class A definition
5264
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M.<global> hidden implicit class A
5365
// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} <line:3:3, col:12> col:8 in M.<global> hidden a 'void ()' implicit-inline
5466

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)?}}
67+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <module.cpp:6:1, line:8:1> line:6:7 in M hidden class Z{{( ReachableWhenImported)?}} definition
68+
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Z{{( ReachableWhenImported)?}}
69+
// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} <line:7:3, col:12> col:8 in M hidden z 'void ()'{{( ReachableWhenImported)?}}
70+
71+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <line:10:1, line:12:1> line:10:7 in M hidden class Inline{{( ReachableWhenImported)?}} definition
72+
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Inline{{( ReachableWhenImported)?}}
73+
// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} <line:11:3, col:19> col:15 in M hidden z 'void ()'{{( ReachableWhenImported)?}} inline
74+
75+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <line:14:1, line:16:1> line:14:7 in M hidden class Constexpr{{( ReachableWhenImported)?}} definition
76+
// CHECK-MOD: | |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Constexpr{{( ReachableWhenImported)?}}
77+
// CHECK-MOD-NEXT: | `-CXXMethodDecl {{.*}} <line:15:3, col:22> col:18 in M hidden constexpr z 'void ()'{{( ReachableWhenImported)?}} implicit-inline
78+
79+
// CHECK-MOD: `-CXXRecordDecl {{.*}} <line:18:1, line:20:1> line:18:7 in M hidden class Consteval{{( ReachableWhenImported)?}} definition
80+
// CHECK-MOD: |-CXXRecordDecl {{.*}} <col:1, col:7> col:7 in M hidden implicit class Consteval{{( ReachableWhenImported)?}}
81+
// CHECK-MOD-NEXT: `-CXXMethodDecl {{.*}} <line:19:3, col:22> col:18 in M hidden consteval z 'void ()'{{( ReachableWhenImported)?}} implicit-inline

0 commit comments

Comments
 (0)