Skip to content

[Clang] Implement CWG 2707 "Deduction guides cannot have a trailing requires-clause" #110473

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 2 commits into from
Sep 30, 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 @@ -205,6 +205,9 @@ Resolutions to C++ Defect Reports
- Reject explicit object parameters with type ``void`` (``this void``).
(`CWG2915: Explicit object parameters of type void <https://cplusplus.github.io/CWG/issues/2915.html>`_).

- Clang now allows trailing requires clause on explicit deduction guides.
(`CWG2707: Deduction guides cannot have a trailing requires-clause <https://cplusplus.github.io/CWG/issues/2707.html>`_).

C Language Changes
------------------

Expand Down
9 changes: 6 additions & 3 deletions clang/include/clang/AST/DeclCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -1965,9 +1965,11 @@ class CXXDeductionGuideDecl : public FunctionDecl {
ExplicitSpecifier ES,
const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, SourceLocation EndLocation,
CXXConstructorDecl *Ctor, DeductionCandidate Kind)
CXXConstructorDecl *Ctor, DeductionCandidate Kind,
Expr *TrailingRequiresClause)
: FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
SC_None, false, false, ConstexprSpecKind::Unspecified),
SC_None, false, false, ConstexprSpecKind::Unspecified,
TrailingRequiresClause),
Ctor(Ctor), ExplicitSpec(ES) {
if (EndLocation.isValid())
setRangeEnd(EndLocation);
Expand All @@ -1987,7 +1989,8 @@ class CXXDeductionGuideDecl : public FunctionDecl {
ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, SourceLocation EndLocation,
CXXConstructorDecl *Ctor = nullptr,
DeductionCandidate Kind = DeductionCandidate::Normal);
DeductionCandidate Kind = DeductionCandidate::Normal,
Expr *TrailingRequiresClause = nullptr);

static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
Expand Down
2 changes: 0 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -3050,8 +3050,6 @@ def note_is_deducible_constraint_evaluated_to_false : Note<
"cannot deduce template arguments for %0 from %1">;
def err_constrained_virtual_method : Error<
"virtual function cannot have a requires clause">;
def err_trailing_requires_clause_on_deduction_guide : Error<
"deduction guide cannot have a requires clause">;
def err_constrained_non_templated_function
: Error<"non-templated function cannot have a requires clause">;
def err_non_temp_spec_requires_clause : Error<
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2211,17 +2211,18 @@ CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, SourceLocation EndLocation, CXXConstructorDecl *Ctor,
DeductionCandidate Kind) {
return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, ES, NameInfo, T,
TInfo, EndLocation, Ctor, Kind);
DeductionCandidate Kind, Expr *TrailingRequiresClause) {
return new (C, DC)
CXXDeductionGuideDecl(C, DC, StartLoc, ES, NameInfo, T, TInfo,
EndLocation, Ctor, Kind, TrailingRequiresClause);
}

CXXDeductionGuideDecl *
CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
return new (C, ID) CXXDeductionGuideDecl(
C, nullptr, SourceLocation(), ExplicitSpecifier(), DeclarationNameInfo(),
QualType(), nullptr, SourceLocation(), nullptr,
DeductionCandidate::Normal);
DeductionCandidate::Normal, nullptr);
}

RequiresExprBodyDecl *RequiresExprBodyDecl::Create(
Expand Down
11 changes: 4 additions & 7 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9293,15 +9293,12 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
TrailingRequiresClause);

} else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
if (TrailingRequiresClause)
SemaRef.Diag(TrailingRequiresClause->getBeginLoc(),
diag::err_trailing_requires_clause_on_deduction_guide)
<< TrailingRequiresClause->getSourceRange();
if (SemaRef.CheckDeductionGuideDeclarator(D, R, SC))
return nullptr;
return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getBeginLoc(),
ExplicitSpecifier, NameInfo, R, TInfo,
D.getEndLoc());
return CXXDeductionGuideDecl::Create(
SemaRef.Context, DC, D.getBeginLoc(), ExplicitSpecifier, NameInfo, R,
TInfo, D.getEndLoc(), /*Ctor=*/nullptr,
/*Kind=*/DeductionCandidate::Normal, TrailingRequiresClause);
} else if (DC->isRecord()) {
// If the name of the function is the same as the name of the record,
// then this must be an invalid constructor that has a return type.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2233,7 +2233,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
SemaRef.Context, DC, D->getInnerLocStart(),
InstantiatedExplicitSpecifier, NameInfo, T, TInfo,
D->getSourceRange().getEnd(), DGuide->getCorrespondingConstructor(),
DGuide->getDeductionCandidateKind());
DGuide->getDeductionCandidateKind(), TrailingRequiresClause);
Function->setAccess(D->getAccess());
} else {
Function = FunctionDecl::Create(
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/dcl/dcl.decl/p3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,4 @@ struct R {
};

template<typename T>
R(T) -> R<T> requires true; // expected-error{{deduction guide cannot have a requires clause}}
R(T) -> R<T> requires true;
28 changes: 28 additions & 0 deletions clang/test/CXX/drs/cwg27xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,31 @@ static_assert(false, f().s);
#endif
} // namespace cwg2798

namespace cwg2707 { // cwg2707: 20
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the number of the Core issue, this test should've been placed towards the beginning of the file. We keep them in the ascending order.


#if __cplusplus >= 202002L

template <class T, unsigned N> struct A {
T value[N];
};

template <typename... T>
A(T...) -> A<int, sizeof...(T)> requires (sizeof...(T) == 2);

// Brace elision is not allowed for synthesized CTAD guides if the array size
// is value-dependent.
// So this should pick up our explicit deduction guide.
A a = {1, 2};

A b = {3, 4, 5};
// expected-error@-1 {{no viable constructor or deduction guide}} \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expected directives should reflect the #if __cplusplus >= 202002L, i.e. since-cxx20-error.

// expected-note@-13 {{candidate function template not viable}} \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DR tests indeed use relative offsets, but they very intentionally avoid making readers count lines to figure out which line the diagnostic is attached to. This should be converted to bookmarks.

// expected-note@-13 {{implicit deduction guide}} \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notes should be indented relative to the error directive they attach to.

// expected-note@-8 {{constraints not satisfied}} \
// expected-note@-8 {{because 'sizeof...(T) == 2' (3 == 2) evaluated to false}} \
// expected-note@-13 {{candidate function template not viable}} \
// expected-note@-13 {{implicit deduction guide}}

#endif

} // namespace cwg2707
4 changes: 2 additions & 2 deletions clang/www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -16089,7 +16089,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2707.html">2707</a></td>
<td>DRWP</td>
<td>Deduction guides cannot have a trailing <I>requires-clause</I></td>
<td class="unknown" align="center">Unknown</td>
<td class="unreleased" align="center">Clang 20</td>
</tr>
<tr id="2708">
<td><a href="https://cplusplus.github.io/CWG/issues/2708.html">2708</a></td>
Expand Down Expand Up @@ -17334,7 +17334,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2913.html">2913</a></td>
<td>tentatively ready</td>
<td>Grammar for <I>deduction-guide</I> has <I>requires-clause</I> in the wrong position</td>
<td align="center">Not resolved</td>
<td class="unreleased" align="center">Clang 20</td>
</tr>
<tr class="open" id="2914">
<td><a href="https://cplusplus.github.io/CWG/issues/2914.html">2914</a></td>
Expand Down
Loading