https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/78139
>From e0eb639c9830599e184aec428164de0b2fb38b71 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Mon, 15 Jan 2024 10:17:13 +0100 Subject: [PATCH 1/2] [Clang] Only compare template params of potential overload after checking their decl context Fixes a regression from 69066ab3 in which we compared the template lists of potential overloads before checkings their declaration contexts. This would cause a crash when doing constraint substitution as part of that template check, because we would try to refer to not yet instantiated entities (the underlying cause is unclear). This patch reorders (again) when we look at templaste parameter so we don't when checkings friends in different lexical contexts. Fixes #77953 Fixes #78101 --- clang/lib/Sema/SemaOverload.cpp | 62 ++++++++++++++----------- clang/test/CXX/over/over.load/p2-0x.cpp | 32 +++++++++++-- clang/test/Modules/GH77953.cpp | 28 +++++++++++ 3 files changed, 89 insertions(+), 33 deletions(-) create mode 100644 clang/test/Modules/GH77953.cpp diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 23b9bc0fe2d6e2..0d1db8d17610b2 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1259,6 +1259,40 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New, if ((OldTemplate == nullptr) != (NewTemplate == nullptr)) return true; + // Is the function New an overload of the function Old? + QualType OldQType = SemaRef.Context.getCanonicalType(Old->getType()); + QualType NewQType = SemaRef.Context.getCanonicalType(New->getType()); + + // Compare the signatures (C++ 1.3.10) of the two functions to + // determine whether they are overloads. If we find any mismatch + // in the signature, they are overloads. + + // If either of these functions is a K&R-style function (no + // prototype), then we consider them to have matching signatures. + if (isa<FunctionNoProtoType>(OldQType.getTypePtr()) || + isa<FunctionNoProtoType>(NewQType.getTypePtr())) + return false; + + const FunctionProtoType *OldType = cast<FunctionProtoType>(OldQType); + const FunctionProtoType *NewType = cast<FunctionProtoType>(NewQType); + + // The signature of a function includes the types of its + // parameters (C++ 1.3.10), which includes the presence or absence + // of the ellipsis; see C++ DR 357). + if (OldQType != NewQType && OldType->isVariadic() != NewType->isVariadic()) + return true; + + // For member-like friends, the enclosing class is part of the signature. + if ((New->isMemberLikeConstrainedFriend() || + Old->isMemberLikeConstrainedFriend()) && + !New->getLexicalDeclContext()->Equals(Old->getLexicalDeclContext())) + return true; + + // Compare the parameter lists. + // This can only be done once we have establish that friend functions + // inhabit the same context, otherwise we might tried to instantiate + // references to non-instantiated entities during constraint substitution. + // GH78101. if (NewTemplate) { // C++ [temp.over.link]p4: // The signature of a function template consists of its function @@ -1296,34 +1330,6 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New, return true; } - // Is the function New an overload of the function Old? - QualType OldQType = SemaRef.Context.getCanonicalType(Old->getType()); - QualType NewQType = SemaRef.Context.getCanonicalType(New->getType()); - - // Compare the signatures (C++ 1.3.10) of the two functions to - // determine whether they are overloads. If we find any mismatch - // in the signature, they are overloads. - - // If either of these functions is a K&R-style function (no - // prototype), then we consider them to have matching signatures. - if (isa<FunctionNoProtoType>(OldQType.getTypePtr()) || - isa<FunctionNoProtoType>(NewQType.getTypePtr())) - return false; - - const FunctionProtoType *OldType = cast<FunctionProtoType>(OldQType); - const FunctionProtoType *NewType = cast<FunctionProtoType>(NewQType); - - // The signature of a function includes the types of its - // parameters (C++ 1.3.10), which includes the presence or absence - // of the ellipsis; see C++ DR 357). - if (OldQType != NewQType && OldType->isVariadic() != NewType->isVariadic()) - return true; - - // For member-like friends, the enclosing class is part of the signature. - if ((New->isMemberLikeConstrainedFriend() || - Old->isMemberLikeConstrainedFriend()) && - !New->getLexicalDeclContext()->Equals(Old->getLexicalDeclContext())) - return true; const auto *OldMethod = dyn_cast<CXXMethodDecl>(Old); const auto *NewMethod = dyn_cast<CXXMethodDecl>(New); diff --git a/clang/test/CXX/over/over.load/p2-0x.cpp b/clang/test/CXX/over/over.load/p2-0x.cpp index 8fd9a1ce1e87ab..a86e2d2a1d81e5 100644 --- a/clang/test/CXX/over/over.load/p2-0x.cpp +++ b/clang/test/CXX/over/over.load/p2-0x.cpp @@ -24,11 +24,6 @@ class Y { void k() &&; // expected-error{{cannot overload a member function with ref-qualifier '&&' with a member function without a ref-qualifier}} }; -struct GH76358 { - template<int> void f() && {} - template<typename T> void f() const {} -}; - #if __cplusplus >= 202002L namespace GH58962 { @@ -55,4 +50,31 @@ static_assert(not test<type<2>&>); static_assert(test<type<2>&&>); } + +namespace GH78101 { + +template<typename T, typename U, int i> +concept True = true; + +template<typename T, int I> +struct Template { + static constexpr int i = I; + friend constexpr auto operator+(True<T, i> auto f) { + return i; + } +}; + +template<int I> +struct Template<float, I> { + static constexpr int i = I; + friend constexpr auto operator+(True<float, i> auto f) { + return i; + } +}; + +Template<void, 4> f{}; +static_assert(+Template<float, 5>{} == 5); + +} + #endif diff --git a/clang/test/Modules/GH77953.cpp b/clang/test/Modules/GH77953.cpp new file mode 100644 index 00000000000000..aaca8153c3d212 --- /dev/null +++ b/clang/test/Modules/GH77953.cpp @@ -0,0 +1,28 @@ +// From https://github.com/llvm/llvm-project/issues/77953 +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/a.cppm -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 -fmodule-file=a=%t/a.pcm %t/b.cppm + +//--- a.cppm +export module a; + +template<typename, typename> +concept c = true; + +export template<typename... Ts> +struct a { + template<typename... Us> requires(... and c<Ts, Us>) + friend bool operator==(a, a<Us...>) { + return true; + } +}; + +template struct a<>; + +//--- b.cppm +import a; + +template struct a<int>; >From 7352ce5f56009337c1d208e61f966f1197acea08 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Mon, 15 Jan 2024 15:40:02 +0100 Subject: [PATCH 2/2] Address review feedback --- clang/lib/Sema/SemaOverload.cpp | 4 ++-- clang/test/CXX/over/over.load/p2-0x.cpp | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 0d1db8d17610b2..dd342df801fe21 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1273,8 +1273,8 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New, isa<FunctionNoProtoType>(NewQType.getTypePtr())) return false; - const FunctionProtoType *OldType = cast<FunctionProtoType>(OldQType); - const FunctionProtoType *NewType = cast<FunctionProtoType>(NewQType); + const auto *OldType = cast<FunctionProtoType>(OldQType); + const auto *NewType = cast<FunctionProtoType>(NewQType); // The signature of a function includes the types of its // parameters (C++ 1.3.10), which includes the presence or absence diff --git a/clang/test/CXX/over/over.load/p2-0x.cpp b/clang/test/CXX/over/over.load/p2-0x.cpp index a86e2d2a1d81e5..94185963ff5c75 100644 --- a/clang/test/CXX/over/over.load/p2-0x.cpp +++ b/clang/test/CXX/over/over.load/p2-0x.cpp @@ -24,6 +24,11 @@ class Y { void k() &&; // expected-error{{cannot overload a member function with ref-qualifier '&&' with a member function without a ref-qualifier}} }; +struct GH76358 { + template<int> void f() && {} + template<typename T> void f() const {} +}; + #if __cplusplus >= 202002L namespace GH58962 { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits