Skip to content

[clang] Implement CWG2428 "Deprecating a concept" #92295

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 10 commits into from
May 17, 2024
Merged
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@ Resolutions to C++ Defect Reports
- Clang now diagnoses declarative nested-name-specifiers with pack-index-specifiers.
(`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers <https://cplusplus.github.io/CWG/issues/2858.html>`_).

- Clang now allows attributes on concepts.
(`CWG2428: Deprecating a concept <https://cplusplus.github.io/CWG/issues/2428.html>`_).

- P0522 implementation is enabled by default in all language versions, and
provisional wording for CWG2398 is implemented.

Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2022,6 +2022,8 @@ class Sema final : public SemaBase {
void CheckTCBEnforcement(const SourceLocation CallExprLoc,
const NamedDecl *Callee);

void CheckConstrainedAuto(const AutoType *AutoT, SourceLocation Loc);

private:
void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
const ArraySubscriptExpr *ASE = nullptr,
Expand Down Expand Up @@ -9356,7 +9358,8 @@ class Sema final : public SemaBase {
Decl *ActOnConceptDefinition(Scope *S,
MultiTemplateParamsArg TemplateParameterLists,
const IdentifierInfo *Name,
SourceLocation NameLoc, Expr *ConstraintExpr);
SourceLocation NameLoc, Expr *ConstraintExpr,
const ParsedAttributesView &Attrs);

void CheckConceptRedefinition(ConceptDecl *NewDecl, LookupResult &Previous,
bool &AddToScope);
Expand Down
17 changes: 11 additions & 6 deletions clang/lib/Parse/ParseTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,13 @@ Parser::DeclGroupPtrTy Parser::ParseTemplateDeclarationOrSpecialization(
LastParamListWasEmpty);

// Parse the actual template declaration.
if (Tok.is(tok::kw_concept))
return Actions.ConvertDeclToDeclGroup(
ParseConceptDefinition(TemplateInfo, DeclEnd));
if (Tok.is(tok::kw_concept)) {
Decl *ConceptDecl = ParseConceptDefinition(TemplateInfo, DeclEnd);
// We need to explicitly pass ConceptDecl to ParsingDeclRAIIObject, so that
// delayed diagnostics (e.g. warn_deprecated) have a Decl to work with.
ParsingTemplateParams.complete(ConceptDecl);
return Actions.ConvertDeclToDeclGroup(ConceptDecl);
}

return ParseDeclarationAfterTemplate(
Context, TemplateInfo, ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
Expand Down Expand Up @@ -316,7 +320,8 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
const IdentifierInfo *Id = Result.Identifier;
SourceLocation IdLoc = Result.getBeginLoc();

DiagnoseAndSkipCXX11Attributes();
ParsedAttributes Attrs(AttrFactory);
MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs);

if (!TryConsumeToken(tok::equal)) {
Diag(Tok.getLocation(), diag::err_expected) << tok::equal;
Expand All @@ -335,8 +340,8 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
Expr *ConstraintExpr = ConstraintExprResult.get();
return Actions.ActOnConceptDefinition(getCurScope(),
*TemplateInfo.TemplateParams,
Id, IdLoc, ConstraintExpr);
*TemplateInfo.TemplateParams, Id, IdLoc,
ConstraintExpr, Attrs);
}

/// ParseTemplateParameters - Parses a template-parameter-list enclosed in
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8092,6 +8092,12 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
diagnoseArgDependentDiagnoseIfAttrs(FD, ThisArg, Args, Loc);
}

void Sema::CheckConstrainedAuto(const AutoType *AutoT, SourceLocation Loc) {
if (ConceptDecl *Decl = AutoT->getTypeConstraintConcept()) {
DiagnoseUseOfDecl(Decl, Loc);
}
}

/// CheckConstructorCall - Check a constructor call for correctness and safety
/// properties not enforced by the C type system.
void Sema::CheckConstructorCall(FunctionDecl *FDecl, QualType ThisType,
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7573,6 +7573,11 @@ NamedDecl *Sema::ActOnVariableDeclarator(
tryToFixVariablyModifiedVarType(TInfo, R, D.getIdentifierLoc(),
/*DiagID=*/0);

if (const AutoType *AutoT = R->getAs<AutoType>())
CheckConstrainedAuto(
AutoT,
TInfo->getTypeLoc().getContainedAutoTypeLoc().getConceptNameLoc());

bool IsMemberSpecialization = false;
bool IsVariableTemplateSpecialization = false;
bool IsPartialSpecialization = false;
Expand Down
8 changes: 7 additions & 1 deletion clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5583,6 +5583,8 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
/*UpdateArgsWithConversions=*/false))
return ExprError();

DiagnoseUseOfDecl(NamedConcept, ConceptNameInfo.getLoc());

auto *CSD = ImplicitConceptSpecializationDecl::Create(
Context, NamedConcept->getDeclContext(), NamedConcept->getLocation(),
CanonicalConverted);
Expand Down Expand Up @@ -9787,7 +9789,8 @@ Decl *Sema::ActOnTemplateDeclarator(Scope *S,

Decl *Sema::ActOnConceptDefinition(
Scope *S, MultiTemplateParamsArg TemplateParameterLists,
const IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr) {
const IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr,
const ParsedAttributesView &Attrs) {
DeclContext *DC = CurContext;

if (!DC->getRedeclContext()->isFileContext()) {
Expand Down Expand Up @@ -9849,6 +9852,9 @@ Decl *Sema::ActOnConceptDefinition(
ActOnDocumentableDecl(NewDecl);
if (AddToScope)
PushOnScopeChains(NewDecl, S);

ProcessDeclAttributeList(S, NewDecl, Attrs);

return NewDecl;
}

Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6388,6 +6388,11 @@ TypeResult Sema::ActOnTypeName(Declarator &D) {
CheckExtraCXXDefaultArguments(D);
}

if (const AutoType *AutoT = T->getAs<AutoType>())
CheckConstrainedAuto(
AutoT,
TInfo->getTypeLoc().getContainedAutoTypeLoc().getConceptNameLoc());

return CreateParsedType(T, TInfo);
}

Expand Down
42 changes: 42 additions & 0 deletions clang/test/CXX/drs/cwg24xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,48 @@ void fallthrough(int n) {
#endif
}

namespace cwg2428 { // cwg2428: 19
#if __cplusplus >= 202002L
template <typename>
concept C [[deprecated]] = true; // #cwg2428-C

template <typename>
[[deprecated]] concept C2 = true;
// expected-error@-1 {{expected unqualified-id}}

template <typename T>
concept C3 = C<T>;
// expected-warning@-1 {{'C' is deprecated}}
// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}}

template <typename T, C U>
// expected-warning@-1 {{'C' is deprecated}}
// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}}
requires C<T>
// expected-warning@-1 {{'C' is deprecated}}
// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}}
void f() {
bool b = C<int>;
// expected-warning@-1 {{'C' is deprecated}}
// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}}
};

void g(C auto a) {};
// expected-warning@-1 {{'C' is deprecated}}
// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}}

template <typename T>
auto h() -> C auto {
// expected-warning@-1 {{'C' is deprecated}}
// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}}
C auto foo = T();
// expected-warning@-1 {{'C' is deprecated}}
// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}}
return foo;
}
#endif
} // namespace cwg2428

namespace cwg2430 { // cwg2430: 2.7
struct S {
S f(S s) { return s; }
Expand Down
12 changes: 11 additions & 1 deletion clang/test/SemaCXX/cxx-deprecated.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s

namespace [[deprecated]] {} // expected-warning {{'deprecated' attribute on anonymous namespace ignored}}

Expand Down Expand Up @@ -27,3 +27,13 @@ namespace M = N; // expected-warning {{'N' is deprecated}}

// Shouldn't diag:
[[nodiscard, deprecated("")]] int PR37935();

namespace cxx20_concept {
template <typename>
concept C __attribute__((deprecated)) = true; // #C

template <C T>
// expected-warning@-1 {{'C' is deprecated}}
// expected-note@#C {{'C' has been explicitly marked deprecated here}}
void f();
} // namespace cxx20_concept
2 changes: 1 addition & 1 deletion clang/www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -14376,7 +14376,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2428.html">2428</a></td>
<td>C++23</td>
<td>Deprecating a concept</td>
<td class="unknown" align="center">Unknown</td>
<td class="unreleased" align="center">Clang 19</td>
</tr>
<tr id="2429">
<td><a href="https://cplusplus.github.io/CWG/issues/2429.html">2429</a></td>
Expand Down