diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 23b9bc0fe2d6e2..dd342df801fe21 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(OldQType.getTypePtr()) || + isa(NewQType.getTypePtr())) + return false; + + const auto *OldType = cast(OldQType); + const auto *NewType = cast(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(OldQType.getTypePtr()) || - isa(NewQType.getTypePtr())) - return false; - - const FunctionProtoType *OldType = cast(OldQType); - const FunctionProtoType *NewType = cast(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(Old); const auto *NewMethod = dyn_cast(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..94185963ff5c75 100644 --- a/clang/test/CXX/over/over.load/p2-0x.cpp +++ b/clang/test/CXX/over/over.load/p2-0x.cpp @@ -55,4 +55,31 @@ static_assert(not test&>); static_assert(test&&>); } + +namespace GH78101 { + +template +concept True = true; + +template +struct Template { + static constexpr int i = I; + friend constexpr auto operator+(True auto f) { + return i; + } +}; + +template +struct Template { + static constexpr int i = I; + friend constexpr auto operator+(True auto f) { + return i; + } +}; + +Template f{}; +static_assert(+Template{} == 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 +concept c = true; + +export template +struct a { + template requires(... and c) + friend bool operator==(a, a) { + return true; + } +}; + +template struct a<>; + +//--- b.cppm +import a; + +template struct a;