Skip to content

Commit 72ac907

Browse files
committed
[C++20] [Modules] Use the canonical decl when getting associated constraints
Close #62943. The root cause for the issue is that we think the associated constraints from the 'same' declaration in different module units are different incorrectly. Since the constraints doesn't know anything about decls and modules, we should fix the problem by getting the associated constraints from the exactly the same declarations from different modules.
1 parent e0743ff commit 72ac907

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

clang/lib/Sema/SemaConcept.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,11 @@ void Sema::DiagnoseUnsatisfiedConstraint(
11551155
const NormalizedConstraint *
11561156
Sema::getNormalizedAssociatedConstraints(
11571157
NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints) {
1158+
// In case the ConstrainedDecl comes from modules, it is necessary to use
1159+
// the canonical decl to avoid different atomic constraints with the 'same'
1160+
// declarations.
1161+
ConstrainedDecl = cast<NamedDecl>(ConstrainedDecl->getCanonicalDecl());
1162+
11581163
auto CacheEntry = NormalizationCache.find(ConstrainedDecl);
11591164
if (CacheEntry == NormalizationCache.end()) {
11601165
auto Normalized =

clang/test/Modules/pr62943.cppm

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: split-file %s %t
4+
//
5+
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm
6+
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.pcm
7+
// RUN: %clang_cc1 -std=c++20 %t/c.cppm -emit-module-interface \
8+
// RUN: -fprebuilt-module-path=%t -o %t/c.pcm
9+
// RUN: %clang_cc1 -std=c++20 %t/use.cpp -fprebuilt-module-path=%t \
10+
// RUN: -fsyntax-only -verify
11+
12+
//--- foo.h
13+
#ifndef FOO_H
14+
#define FOO_H
15+
16+
template<class _Tp>
17+
concept __has_member_value_type = requires { typename _Tp::value_type; };
18+
19+
template<class _Tp>
20+
concept __has_member_element_type = requires { typename _Tp::element_type; };
21+
22+
template <class _Tp>
23+
inline constexpr bool is_object_v = __is_object(_Tp);
24+
25+
template<class> struct __cond_value_type {};
26+
27+
template<class _Tp>
28+
requires is_object_v<_Tp>
29+
struct __cond_value_type<_Tp> { using value_type = bool; };
30+
31+
template<class> struct indirectly_readable_traits {
32+
static constexpr int value = false;
33+
};
34+
#endif
35+
36+
//--- foo.member_value_type.h
37+
#include "foo.h"
38+
template<__has_member_value_type _Tp>
39+
struct indirectly_readable_traits<_Tp> : __cond_value_type<typename _Tp::value_type> {
40+
static constexpr int value = false;
41+
};
42+
43+
//--- foo.memeber_element_type.h
44+
#include "foo.h"
45+
template<__has_member_element_type _Tp>
46+
struct indirectly_readable_traits<_Tp> : __cond_value_type<typename _Tp::element_type> {
47+
static constexpr int value = false;
48+
};
49+
50+
template<__has_member_value_type _Tp>
51+
requires __has_member_element_type<_Tp>
52+
struct indirectly_readable_traits<_Tp> {
53+
static constexpr int value = true;
54+
};
55+
56+
//--- foo.a.h
57+
#include "foo.h"
58+
#include "foo.member_value_type.h"
59+
#include "foo.memeber_element_type.h"
60+
template <typename T>
61+
using AType = indirectly_readable_traits<T>;
62+
63+
//--- a.cppm
64+
module;
65+
#include "foo.a.h"
66+
export module a;
67+
68+
export using ::AType;
69+
70+
//--- b.cppm
71+
module;
72+
#include "foo.h"
73+
#include "foo.memeber_element_type.h"
74+
export module b;
75+
76+
//--- c.cppm
77+
export module c;
78+
79+
export import a;
80+
export import b;
81+
82+
//--- use.cpp
83+
// expected-no-diagnostics
84+
import c;
85+
86+
template <typename T>
87+
class U {
88+
public:
89+
using value_type = T;
90+
using element_type = T;
91+
};
92+
93+
template <typename T>
94+
class V {
95+
public:
96+
};
97+
98+
static_assert(!AType<V<int*>>::value);
99+
static_assert(AType<U<int**>>::value);

0 commit comments

Comments
 (0)