Skip to content

[clang] concepts: perform parameter mapping substitution in correct context #101745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ Bug Fixes to C++ Support
with a string literal. (#GH82167)
- Fix a crash when matching template template parameters with templates which have
parameters of different class type. (#GH101394)
- Clang now correctly recognizes the correct context for parameter
substitutions in concepts, so it doesn't incorrectly complain of missing
module imports in those situations. (#GH60336)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
5 changes: 3 additions & 2 deletions clang/include/clang/Sema/SemaConcept.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ enum { ConstraintAlignment = 8 };

struct alignas(ConstraintAlignment) AtomicConstraint {
const Expr *ConstraintExpr;
NamedDecl *ConstraintDecl;
std::optional<ArrayRef<TemplateArgumentLoc>> ParameterMapping;

AtomicConstraint(Sema &S, const Expr *ConstraintExpr) :
ConstraintExpr(ConstraintExpr) { };
AtomicConstraint(const Expr *ConstraintExpr, NamedDecl *ConstraintDecl)
: ConstraintExpr(ConstraintExpr), ConstraintDecl(ConstraintDecl) {};

bool hasMatchingParameterMapping(ASTContext &C,
const AtomicConstraint &Other) const {
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Sema/SemaConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1457,8 +1457,8 @@ substituteParameterMappings(Sema &S, NormalizedConstraint &N,
: ArgsAsWritten->arguments().front().getSourceRange().getEnd();
Sema::InstantiatingTemplate Inst(
S, InstLocBegin,
Sema::InstantiatingTemplate::ParameterMappingSubstitution{}, Concept,
{InstLocBegin, InstLocEnd});
Sema::InstantiatingTemplate::ParameterMappingSubstitution{},
Atomic.ConstraintDecl, {InstLocBegin, InstLocEnd});
if (Inst.isInvalid())
return true;
if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs))
Expand Down Expand Up @@ -1632,7 +1632,7 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
Kind, std::move(*Sub), FE->getPattern()}};
}

return NormalizedConstraint{new (S.Context) AtomicConstraint(S, E)};
return NormalizedConstraint{new (S.Context) AtomicConstraint(E, D)};
}

bool FoldExpandedConstraint::AreCompatibleForSubsumption(
Expand Down
44 changes: 44 additions & 0 deletions clang/test/Modules/GH60336-2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -x c++ -std=c++20 %s -verify -fmodules -fmodules-cache-path=%t
// expected-no-diagnostics

#pragma clang module build std
module std {
module concepts {}
module functional {}
}
#pragma clang module contents
#pragma clang module begin std

template <class _Tp> struct common_reference {
using type = _Tp;
};

#pragma clang module end
#pragma clang module begin std.concepts
#pragma clang module import std

template <class _Tp>
concept same_as = __is_same(_Tp, _Tp);

template <class _Tp>
concept common_reference_with =
same_as<typename common_reference<_Tp>::type>;

#pragma clang module end
#pragma clang module begin std.functional
#pragma clang module import std.concepts

template <class, class _Ip>
concept sentinel_for = common_reference_with<_Ip>;

constexpr bool ntsf_subsumes_sf(sentinel_for<char *> auto)
requires true
{
return true;
}
bool ntsf_subsumes_sf(sentinel_for<char *> auto);
static_assert(ntsf_subsumes_sf(""));

#pragma clang module end
#pragma clang module endbuild
13 changes: 2 additions & 11 deletions clang/test/Modules/GH60336.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -x c++ -std=c++20 %s -verify -fmodules -fmodules-cache-path=%t
// expected-no-diagnostics

#pragma clang module build std
module std [system] {
module concepts [system] {
Expand Down Expand Up @@ -65,14 +67,3 @@ constexpr bool ntsf_subsumes_sf(std::nothrow_sentinel_for<char*> auto) requires
}
constexpr bool ntsf_subsumes_sf(std::sentinel_for<char*> auto);
static_assert(ntsf_subsumes_sf("foo"));

// Note: Doing diagnostics verify lines in the individual modules isn't
// permitted, and using 'bookmarks' in a module also doesn't work, so we're
// forced to diagnose this by line-number.
//
// Check to ensure that this error happens, prior to a revert of a concepts
// sugaring patch, this diagnostic didn't happen correctly.

// expected-error@* {{partial specialization of 'common_reference<_Tp, _Up>' must be imported from module 'std.type_traits' before it is required}}
// expected-note@63 {{while substituting into concept arguments here}}
// expected-note@*{{partial specialization declared here is not reachable}}
Loading