forked from CTSRD-CHERI/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[C++20] [Modules] Allow Stmt::Profile to treat lambdas as equal condi…
…tionally Close llvm/llvm-project#63544. Background: We landed std modules in libcxx recently but we haven't landed the corresponding in-tree tests. According to @mordante, there are only 1% libcxx tests failing with std modules. And the major blocking issue is the lambda expression in the require clauses. The root cause of the issue is that previously we never consider any lambda expression as the same. Per [temp.over.link]p5: > Two lambda-expressions are never considered equivalent. I thought this is an oversight at first but @rsmith explains that in the wording, the program is as if there is only a single definition, and a single lambda-expression. So we don't need worry about this in the spec. The explanation makes sense. But it didn't reflect to the implementation directly. Here is a cycle in the implementation. If we want to merge two definitions, we need to make sure its implementation are the same. But according to the explanation above, we need to judge if two lambda-expression are the same by looking at its parent definitions. So here is the problem. To solve the problem, I think we have to profile the lambda expressions actually to get the accurate information. But we can't do this universally. So in this patch I tried to modify the interface of `Stmt::Profile` and only profile the lambda expression during the process of merging the constraint expressions. Differential Revision: https://reviews.llvm.org/D153957
- Loading branch information
Showing
5 changed files
with
230 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// Tests that we can merge the concept declarations with lambda well. | ||
// | ||
// RUN: rm -rf %t | ||
// RUN: mkdir -p %t | ||
// RUN: split-file %s %t | ||
// | ||
// RUN: %clang_cc1 -std=c++20 %t/A.cppm -emit-module-interface -o %t/A.pcm | ||
// RUN: %clang_cc1 -std=c++20 %t/A0.cppm -emit-module-interface -o %t/A0.pcm | ||
// RUN: %clang_cc1 -std=c++20 %t/TestA.cpp -fprebuilt-module-path=%t -fsyntax-only -verify | ||
// | ||
// RUN: %clang_cc1 -std=c++20 %t/A1.cppm -emit-module-interface -o %t/A1.pcm | ||
// RUN: %clang_cc1 -std=c++20 %t/TestA1.cpp -fprebuilt-module-path=%t -fsyntax-only -verify | ||
// | ||
// RUN: %clang_cc1 -std=c++20 %t/A2.cppm -emit-module-interface -o %t/A2.pcm | ||
// RUN: %clang_cc1 -std=c++20 %t/TestA2.cpp -fprebuilt-module-path=%t -fsyntax-only -verify | ||
// | ||
// RUN: %clang_cc1 -std=c++20 %t/A3.cppm -emit-module-interface -o %t/A3.pcm | ||
// RUN: %clang_cc1 -std=c++20 %t/TestA3.cpp -fprebuilt-module-path=%t -fsyntax-only -verify | ||
|
||
//--- A.h | ||
template <class _Tp> | ||
concept A = requires(const _Tp& __t) { []<class __Up>(const __Up&) {}(__t); }; | ||
|
||
//--- A1.h | ||
template <class _Tp> | ||
concept A = requires(const _Tp& __t) { []<class __Up>(__Up) {}(__t); }; | ||
|
||
//--- A2.h | ||
template <class _Tp> | ||
concept A = requires(const _Tp& __t) { []<class __Up>(const __Up& __u) { | ||
(int)__u; | ||
}(__t); }; | ||
|
||
//--- A3.h | ||
template <class _Tp> | ||
concept A = requires(const _Tp& __t) { [t = '?']<class __Up>(const __Up&) { | ||
(int)t; | ||
}(__t); }; | ||
|
||
//--- A.cppm | ||
module; | ||
#include "A.h" | ||
export module A; | ||
export using ::A; | ||
|
||
//--- A0.cppm | ||
module; | ||
#include "A.h" | ||
export module A0; | ||
export using ::A; | ||
|
||
//--- TestA.cpp | ||
// expected-no-diagnostics | ||
import A; | ||
import A0; | ||
|
||
template <class C> | ||
void f(C) requires(A<C>) {} | ||
|
||
//--- A1.cppm | ||
module; | ||
#include "A1.h" | ||
export module A1; | ||
export using ::A; | ||
|
||
//--- TestA1.cpp | ||
import A; | ||
import A1; | ||
|
||
template <class C> | ||
void f(C) requires(A<C>) {} // expected-error 1+{{reference to 'A' is ambiguous}} | ||
// expected-note@* 1+{{candidate found by name lookup is 'A'}} | ||
|
||
//--- A2.cppm | ||
module; | ||
#include "A2.h" | ||
export module A2; | ||
export using ::A; | ||
|
||
//--- TestA2.cpp | ||
import A; | ||
import A2; | ||
|
||
template <class C> | ||
void f(C) requires(A<C>) {} // expected-error 1+{{reference to 'A' is ambiguous}} | ||
// expected-note@* 1+{{candidate found by name lookup is 'A'}} | ||
|
||
//--- A3.cppm | ||
module; | ||
#include "A3.h" | ||
export module A3; | ||
export using ::A; | ||
|
||
//--- TestA3.cpp | ||
import A; | ||
import A3; | ||
|
||
template <class C> | ||
void f(C) requires(A<C>) {} // expected-error 1+{{reference to 'A' is ambiguous}} | ||
// expected-note@* 1+{{candidate found by name lookup is 'A'}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// RUN: rm -rf %t | ||
// RUN: mkdir -p %t | ||
// RUN: split-file %s %t | ||
// | ||
// RUN: %clang_cc1 -std=c++23 %t/a.cppm -emit-module-interface -o %t/m-a.pcm | ||
// RUN: %clang_cc1 -std=c++23 %t/b.cppm -emit-module-interface -o %t/m-b.pcm | ||
// RUN: %clang_cc1 -std=c++23 %t/m.cppm -emit-module-interface -o %t/m.pcm \ | ||
// RUN: -fprebuilt-module-path=%t | ||
// RUN: %clang_cc1 -std=c++23 %t/pr63544.cpp -fprebuilt-module-path=%t -fsyntax-only -verify | ||
|
||
//--- foo.h | ||
|
||
namespace std { | ||
struct strong_ordering { | ||
int n; | ||
constexpr operator int() const { return n; } | ||
static const strong_ordering equal, greater, less; | ||
}; | ||
constexpr strong_ordering strong_ordering::equal = {0}; | ||
constexpr strong_ordering strong_ordering::greater = {1}; | ||
constexpr strong_ordering strong_ordering::less = {-1}; | ||
} // namespace std | ||
|
||
namespace std { | ||
template <typename _Tp> | ||
class optional { | ||
private: | ||
using value_type = _Tp; | ||
value_type __val_; | ||
bool __engaged_; | ||
public: | ||
constexpr bool has_value() const noexcept | ||
{ | ||
return this->__engaged_; | ||
} | ||
|
||
constexpr const value_type& operator*() const& noexcept | ||
{ | ||
return __val_; | ||
} | ||
|
||
optional(_Tp v) : __val_(v) { | ||
__engaged_ = true; | ||
} | ||
}; | ||
|
||
template <class _Tp> | ||
concept __is_derived_from_optional = requires(const _Tp& __t) { []<class __Up>(const optional<__Up>&) {}(__t); }; | ||
|
||
template <class _Tp, class _Up> | ||
requires(!__is_derived_from_optional<_Up>) | ||
constexpr strong_ordering | ||
operator<=>(const optional<_Tp>& __x, const _Up& __v) { | ||
return __x.has_value() ? *__x <=> __v : strong_ordering::less; | ||
} | ||
} // namespace std | ||
|
||
//--- a.cppm | ||
module; | ||
#include "foo.h" | ||
export module m:a; | ||
export namespace std { | ||
using std::optional; | ||
using std::operator<=>; | ||
} | ||
|
||
//--- b.cppm | ||
module; | ||
#include "foo.h" | ||
export module m:b; | ||
export namespace std { | ||
using std::optional; | ||
using std::operator<=>; | ||
} | ||
|
||
//--- m.cppm | ||
export module m; | ||
export import :a; | ||
export import :b; | ||
|
||
//--- pr63544.cpp | ||
// expected-no-diagnostics | ||
import m; | ||
int pr63544() { | ||
std::optional<int> a(43); | ||
int t{3}; | ||
return a<=>t; | ||
} |