diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index ae699ebfc6038..1f51879e914f2 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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 `_). +- Clang now allows attributes on concepts. + (`CWG2428: Deprecating a concept `_). + - P0522 implementation is enabled by default in all language versions, and provisional wording for CWG2398 is implemented. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 6a414aa57f32b..0bb145659eca1 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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, @@ -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); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 665253a6674d2..8f841be422dd8 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -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); @@ -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; @@ -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 diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index ecd1821651140..f2dc8e9dd0050 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -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, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0dbdf923df95a..bb0bee0d234c5 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -7573,6 +7573,11 @@ NamedDecl *Sema::ActOnVariableDeclarator( tryToFixVariablyModifiedVarType(TInfo, R, D.getIdentifierLoc(), /*DiagID=*/0); + if (const AutoType *AutoT = R->getAs()) + CheckConstrainedAuto( + AutoT, + TInfo->getTypeLoc().getContainedAutoTypeLoc().getConceptNameLoc()); + bool IsMemberSpecialization = false; bool IsVariableTemplateSpecialization = false; bool IsPartialSpecialization = false; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index c7aac068e264b..2da933896b4da 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -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); @@ -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()) { @@ -9849,6 +9852,9 @@ Decl *Sema::ActOnConceptDefinition( ActOnDocumentableDecl(NewDecl); if (AddToScope) PushOnScopeChains(NewDecl, S); + + ProcessDeclAttributeList(S, NewDecl, Attrs); + return NewDecl; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index eb67546d048ae..2394aad6d25f9 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -6388,6 +6388,11 @@ TypeResult Sema::ActOnTypeName(Declarator &D) { CheckExtraCXXDefaultArguments(D); } + if (const AutoType *AutoT = T->getAs()) + CheckConstrainedAuto( + AutoT, + TInfo->getTypeLoc().getContainedAutoTypeLoc().getConceptNameLoc()); + return CreateParsedType(T, TInfo); } diff --git a/clang/test/CXX/drs/cwg24xx.cpp b/clang/test/CXX/drs/cwg24xx.cpp index 75e1a614765c5..4c7b1506e86ea 100644 --- a/clang/test/CXX/drs/cwg24xx.cpp +++ b/clang/test/CXX/drs/cwg24xx.cpp @@ -45,6 +45,48 @@ void fallthrough(int n) { #endif } +namespace cwg2428 { // cwg2428: 19 +#if __cplusplus >= 202002L +template +concept C [[deprecated]] = true; // #cwg2428-C + +template +[[deprecated]] concept C2 = true; +// expected-error@-1 {{expected unqualified-id}} + +template +concept C3 = C; +// expected-warning@-1 {{'C' is deprecated}} +// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}} + +template +// expected-warning@-1 {{'C' is deprecated}} +// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}} +requires C +// expected-warning@-1 {{'C' is deprecated}} +// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}} +void f() { + bool b = C; + // 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 +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; } diff --git a/clang/test/SemaCXX/cxx-deprecated.cpp b/clang/test/SemaCXX/cxx-deprecated.cpp index aa4501d53197a..81eb07608300d 100644 --- a/clang/test/SemaCXX/cxx-deprecated.cpp +++ b/clang/test/SemaCXX/cxx-deprecated.cpp @@ -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}} @@ -27,3 +27,13 @@ namespace M = N; // expected-warning {{'N' is deprecated}} // Shouldn't diag: [[nodiscard, deprecated("")]] int PR37935(); + +namespace cxx20_concept { +template +concept C __attribute__((deprecated)) = true; // #C + +template +// expected-warning@-1 {{'C' is deprecated}} +// expected-note@#C {{'C' has been explicitly marked deprecated here}} +void f(); +} // namespace cxx20_concept diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index abf5d4ae4676d..7c1f1c246f5ea 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -14376,7 +14376,7 @@

C++ defect report implementation status

2428 C++23 Deprecating a concept - Unknown + Clang 19 2429