https://github.com/a-tarasyuk updated https://github.com/llvm/llvm-project/pull/122621
>From b2c656afdf99eff52d019b68fcbbc6ce4bbdd7d3 Mon Sep 17 00:00:00 2001 From: Oleksandr T <oleksandr.taras...@outlook.com> Date: Sun, 12 Jan 2025 00:51:47 +0200 Subject: [PATCH 1/8] [Clang] disallow the use of asterisks preceding constructor and destructor names --- clang/docs/ReleaseNotes.rst | 1 + clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 ++++ clang/lib/Sema/SemaDeclCXX.cpp | 13 +++++++++++++ clang/test/SemaCXX/constructor.cpp | 10 ++++++++++ clang/test/SemaCXX/destructor.cpp | 7 +++++++ 5 files changed, 35 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 197b3692b8a181..9e5bbbf6dc055a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -764,6 +764,7 @@ Improvements to Clang's diagnostics scope.Unlock(); require(scope); // Warning! Requires mu1. } +- Clang now disallows the use of asterisks preceding constructor and destructor names (#GH121706). Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index d4e897868f1a9a..ec0be4ea8b6ce0 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2202,6 +2202,8 @@ def err_invalid_qualified_constructor : Error< "'%0' qualifier is not allowed on a constructor">; def err_ref_qualifier_constructor : Error< "ref-qualifier '%select{&&|&}0' is not allowed on a constructor">; +def err_invalid_constructor_decl : Error< + "invalid constructor declaration">; def err_constructor_return_type : Error< "constructor cannot have a return type">; @@ -2223,6 +2225,8 @@ def err_destructor_not_member : Error< def err_destructor_cannot_be : Error<"destructor cannot be declared '%0'">; def err_invalid_qualified_destructor : Error< "'%0' qualifier is not allowed on a destructor">; +def err_invalid_destructor_decl : Error< + "invalid destructor declaration">; def err_ref_qualifier_destructor : Error< "ref-qualifier '%select{&&|&}0' is not allowed on a destructor">; def err_destructor_return_type : Error<"destructor cannot have a return type">; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index c4bee44f5ec048..bb6f6e14713d9b 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -10757,6 +10757,17 @@ static void checkMethodTypeQualifiers(Sema &S, Declarator &D, unsigned DiagID) { } } +static void checkMethodPointerType(Sema &S, Declarator &D, unsigned DiagID) { + if (D.getNumTypeObjects() > 0) { + DeclaratorChunk &Chunk = D.getTypeObject(D.getNumTypeObjects() - 1); + if (Chunk.Kind == DeclaratorChunk::Pointer) { + SourceLocation PointerLoc = Chunk.getSourceRange().getBegin(); + S.Diag(PointerLoc, DiagID) << Chunk.getSourceRange(); + D.setInvalidType(); + } + } +} + QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, StorageClass &SC) { bool isVirtual = D.getDeclSpec().isVirtualSpecified(); @@ -10792,6 +10803,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, } checkMethodTypeQualifiers(*this, D, diag::err_invalid_qualified_constructor); + checkMethodPointerType(*this, D, diag::err_invalid_constructor_decl); // C++0x [class.ctor]p4: // A constructor shall not be declared with a ref-qualifier. @@ -10958,6 +10970,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, } checkMethodTypeQualifiers(*this, D, diag::err_invalid_qualified_destructor); + checkMethodPointerType(*this, D, diag::err_invalid_destructor_decl); // C++0x [class.dtor]p2: // A destructor shall not be declared with a ref-qualifier. diff --git a/clang/test/SemaCXX/constructor.cpp b/clang/test/SemaCXX/constructor.cpp index abd7dbe18a0e6a..c6df7be25c1fac 100644 --- a/clang/test/SemaCXX/constructor.cpp +++ b/clang/test/SemaCXX/constructor.cpp @@ -96,3 +96,13 @@ namespace PR38286 { template<typename> struct C; // expected-note {{non-type declaration found}} template<typename T> C<T>::~C() {} // expected-error {{identifier 'C' after '~' in destructor name does not name a type}} } + +namespace GH121706 { +struct S { + *S(); // expected-error {{invalid constructor declaration}} + **S(); // expected-error {{invalid constructor declaration}} + + **S(const S &); // expected-error {{invalid constructor declaration}} + *S(S &&); // expected-error {{invalid constructor declaration}} +}; +} diff --git a/clang/test/SemaCXX/destructor.cpp b/clang/test/SemaCXX/destructor.cpp index dfcd1b033af5a2..f188e95c25d174 100644 --- a/clang/test/SemaCXX/destructor.cpp +++ b/clang/test/SemaCXX/destructor.cpp @@ -586,4 +586,11 @@ struct Y : X {} y1{ }; // expected-error {{call to implicitly-deleted default co // expected-note {{default constructor of 'Y' is implicitly deleted because base class 'X' has no destructor}} } +namespace GH121706 { +struct S { + *~S(); // expected-error {{invalid destructor declaration}} + **~S(); // expected-error {{invalid destructor declaration}} +}; +} + #endif // BE_THE_HEADER >From 144d0f35aabf0f02d0a90b8cd124f3f11bd65244 Mon Sep 17 00:00:00 2001 From: Oleksandr T <oleksandr.taras...@outlook.com> Date: Sun, 12 Jan 2025 14:50:59 +0200 Subject: [PATCH 2/8] skip invalid type checks --- clang/lib/Sema/SemaDeclCXX.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index bb6f6e14713d9b..b339ee95d75f15 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -10758,6 +10758,9 @@ static void checkMethodTypeQualifiers(Sema &S, Declarator &D, unsigned DiagID) { } static void checkMethodPointerType(Sema &S, Declarator &D, unsigned DiagID) { + if (D.isInvalidType()) + return; + if (D.getNumTypeObjects() > 0) { DeclaratorChunk &Chunk = D.getTypeObject(D.getNumTypeObjects() - 1); if (Chunk.Kind == DeclaratorChunk::Pointer) { >From 13951a404b92b29969ea688343335b5f391fdb9e Mon Sep 17 00:00:00 2001 From: Oleksandr T <oleksandr.taras...@outlook.com> Date: Mon, 13 Jan 2025 15:33:48 +0200 Subject: [PATCH 3/8] handle all invalid declarator chunks for ctor, dtor --- clang/lib/Sema/SemaDeclCXX.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index b339ee95d75f15..d4a96daea39a3c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -10757,18 +10757,19 @@ static void checkMethodTypeQualifiers(Sema &S, Declarator &D, unsigned DiagID) { } } -static void checkMethodPointerType(Sema &S, Declarator &D, unsigned DiagID) { - if (D.isInvalidType()) +static void diagnoseInvalidDeclaratorChunks(Sema &S, Declarator &D, + unsigned DiagID) { + if (D.isInvalidType() || D.getNumTypeObjects() <= 1) return; - if (D.getNumTypeObjects() > 0) { - DeclaratorChunk &Chunk = D.getTypeObject(D.getNumTypeObjects() - 1); - if (Chunk.Kind == DeclaratorChunk::Pointer) { - SourceLocation PointerLoc = Chunk.getSourceRange().getBegin(); - S.Diag(PointerLoc, DiagID) << Chunk.getSourceRange(); - D.setInvalidType(); - } - } + DeclaratorChunk &Chunk = D.getTypeObject(D.getNumTypeObjects() - 1); + if (Chunk.Kind == DeclaratorChunk::Paren || + Chunk.Kind == DeclaratorChunk::Function) + return; + + SourceLocation PointerLoc = Chunk.getSourceRange().getBegin(); + S.Diag(PointerLoc, DiagID) << Chunk.getSourceRange(); + D.setInvalidType(); } QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, @@ -10806,7 +10807,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, } checkMethodTypeQualifiers(*this, D, diag::err_invalid_qualified_constructor); - checkMethodPointerType(*this, D, diag::err_invalid_constructor_decl); + diagnoseInvalidDeclaratorChunks(*this, D, diag::err_invalid_constructor_decl); // C++0x [class.ctor]p4: // A constructor shall not be declared with a ref-qualifier. @@ -10973,7 +10974,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, } checkMethodTypeQualifiers(*this, D, diag::err_invalid_qualified_destructor); - checkMethodPointerType(*this, D, diag::err_invalid_destructor_decl); + diagnoseInvalidDeclaratorChunks(*this, D, diag::err_invalid_destructor_decl); // C++0x [class.dtor]p2: // A destructor shall not be declared with a ref-qualifier. >From 9389a6c0435a5316b8f0a5799a934b610750d484 Mon Sep 17 00:00:00 2001 From: Oleksandr T <oleksandr.taras...@outlook.com> Date: Mon, 13 Jan 2025 15:33:58 +0200 Subject: [PATCH 4/8] add additional tests --- clang/test/SemaCXX/constructor.cpp | 46 ++++++++++++++++++++++++++---- clang/test/SemaCXX/destructor.cpp | 45 +++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/clang/test/SemaCXX/constructor.cpp b/clang/test/SemaCXX/constructor.cpp index c6df7be25c1fac..2e4e442d571993 100644 --- a/clang/test/SemaCXX/constructor.cpp +++ b/clang/test/SemaCXX/constructor.cpp @@ -98,11 +98,47 @@ namespace PR38286 { } namespace GH121706 { -struct S { - *S(); // expected-error {{invalid constructor declaration}} - **S(); // expected-error {{invalid constructor declaration}} +struct A { + *&A(); // expected-error {{invalid constructor declaration}} +}; + +struct B { + *&&B(); // expected-error {{invalid constructor declaration}} +}; + +struct C { + *const C(); // expected-error {{invalid constructor declaration}} +}; + +struct D { + *const *D(); // expected-error {{invalid constructor declaration}} +}; + +struct E { + *E::*E(); // expected-error {{invalid constructor declaration}} +}; + +struct F { + *F::*const F(); // expected-error {{invalid constructor declaration}} +}; + +struct G { + ****G(); // expected-error {{invalid constructor declaration}} +}; + +struct H { + **H(const H &); // expected-error {{invalid constructor declaration}} +}; + +struct I { + *I(I &&); // expected-error {{invalid constructor declaration}} +}; + +struct J { + *&(J)(); // expected-error {{invalid constructor declaration}} +}; - **S(const S &); // expected-error {{invalid constructor declaration}} - *S(S &&); // expected-error {{invalid constructor declaration}} +struct K { + **&&(K)(); // expected-error {{invalid constructor declaration}} }; } diff --git a/clang/test/SemaCXX/destructor.cpp b/clang/test/SemaCXX/destructor.cpp index f188e95c25d174..589616ef8e437b 100644 --- a/clang/test/SemaCXX/destructor.cpp +++ b/clang/test/SemaCXX/destructor.cpp @@ -587,9 +587,48 @@ struct Y : X {} y1{ }; // expected-error {{call to implicitly-deleted default co } namespace GH121706 { -struct S { - *~S(); // expected-error {{invalid destructor declaration}} - **~S(); // expected-error {{invalid destructor declaration}} +struct A { + *&~A(); // expected-error {{invalid destructor declaration}} +}; + +struct B { + *&&~B(); // expected-error {{invalid destructor declaration}} +}; + +struct C { + *const ~C(); // expected-error {{invalid destructor declaration}} +}; + +struct D { + *const * ~D(); // expected-error {{invalid destructor declaration}} +}; + +struct E { + *E::*~E(); // expected-error {{invalid destructor declaration}} +}; + +struct F { + *F::*const ~F(); // expected-error {{invalid destructor declaration}} +}; + +struct G { + ****~G(); // expected-error {{invalid destructor declaration}} +}; + +struct H { + **~H(); // expected-error {{invalid destructor declaration}} +}; + +struct I { + *~I(); // expected-error {{invalid destructor declaration}} +}; + +struct J { + *&~J(); // expected-error {{invalid destructor declaration}} +}; + +struct K { + **&&~K(); // expected-error {{invalid destructor declaration}} }; } >From e5bd3e6daa6c8786e002d8a3e59609c299a71eea Mon Sep 17 00:00:00 2001 From: Oleksandr T <oleksandr.taras...@outlook.com> Date: Mon, 13 Jan 2025 19:27:24 +0200 Subject: [PATCH 5/8] change diagnostic message --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 6 ++---- clang/lib/Sema/SemaDeclCXX.cpp | 9 +++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ec0be4ea8b6ce0..0fe1ad08c6388e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2202,8 +2202,8 @@ def err_invalid_qualified_constructor : Error< "'%0' qualifier is not allowed on a constructor">; def err_ref_qualifier_constructor : Error< "ref-qualifier '%select{&&|&}0' is not allowed on a constructor">; -def err_invalid_constructor_decl : Error< - "invalid constructor declaration">; +def err_invalid_ctor_dtor_decl : Error< + "invalid %select{constructor|destructor}0 declaration">; def err_constructor_return_type : Error< "constructor cannot have a return type">; @@ -2225,8 +2225,6 @@ def err_destructor_not_member : Error< def err_destructor_cannot_be : Error<"destructor cannot be declared '%0'">; def err_invalid_qualified_destructor : Error< "'%0' qualifier is not allowed on a destructor">; -def err_invalid_destructor_decl : Error< - "invalid destructor declaration">; def err_ref_qualifier_destructor : Error< "ref-qualifier '%select{&&|&}0' is not allowed on a destructor">; def err_destructor_return_type : Error<"destructor cannot have a return type">; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index d4a96daea39a3c..06cdc8044aef9d 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -10758,7 +10758,7 @@ static void checkMethodTypeQualifiers(Sema &S, Declarator &D, unsigned DiagID) { } static void diagnoseInvalidDeclaratorChunks(Sema &S, Declarator &D, - unsigned DiagID) { + unsigned Kind) { if (D.isInvalidType() || D.getNumTypeObjects() <= 1) return; @@ -10768,7 +10768,8 @@ static void diagnoseInvalidDeclaratorChunks(Sema &S, Declarator &D, return; SourceLocation PointerLoc = Chunk.getSourceRange().getBegin(); - S.Diag(PointerLoc, DiagID) << Chunk.getSourceRange(); + S.Diag(PointerLoc, diag::err_invalid_ctor_dtor_decl) + << Kind << Chunk.getSourceRange(); D.setInvalidType(); } @@ -10807,7 +10808,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, } checkMethodTypeQualifiers(*this, D, diag::err_invalid_qualified_constructor); - diagnoseInvalidDeclaratorChunks(*this, D, diag::err_invalid_constructor_decl); + diagnoseInvalidDeclaratorChunks(*this, D, /*constructor*/ 0); // C++0x [class.ctor]p4: // A constructor shall not be declared with a ref-qualifier. @@ -10974,7 +10975,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, } checkMethodTypeQualifiers(*this, D, diag::err_invalid_qualified_destructor); - diagnoseInvalidDeclaratorChunks(*this, D, diag::err_invalid_destructor_decl); + diagnoseInvalidDeclaratorChunks(*this, D, /*destructor*/ 1); // C++0x [class.dtor]p2: // A destructor shall not be declared with a ref-qualifier. >From 1fb1a8a95476bb583337873ecb795e9c3a81f419 Mon Sep 17 00:00:00 2001 From: Oleksandr T <oleksandr.taras...@outlook.com> Date: Mon, 13 Jan 2025 19:27:33 +0200 Subject: [PATCH 6/8] add tests --- clang/test/SemaCXX/constructor.cpp | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/clang/test/SemaCXX/constructor.cpp b/clang/test/SemaCXX/constructor.cpp index 2e4e442d571993..b069d55118f567 100644 --- a/clang/test/SemaCXX/constructor.cpp +++ b/clang/test/SemaCXX/constructor.cpp @@ -98,6 +98,7 @@ namespace PR38286 { } namespace GH121706 { + struct A { *&A(); // expected-error {{invalid constructor declaration}} }; @@ -141,4 +142,34 @@ struct J { struct K { **&&(K)(); // expected-error {{invalid constructor declaration}} }; + +struct L { + *L(L&& other); // expected-error {{invalid constructor declaration}} +}; + +struct M { + *M(M& other); // expected-error {{invalid constructor declaration}} +}; + +struct N { + int N(); // expected-error {{constructor cannot have a return type}} +}; + +struct O { + static O(); // expected-error {{constructor cannot be declared 'static'}} +}; + +struct P { + explicit P(); +}; + +struct Q { + constexpr Q(); +}; + +struct R { + R(); + friend R::R(); +}; + } >From a6766e9309742a531a3e78ebf63283ea7fa5ed68 Mon Sep 17 00:00:00 2001 From: Oleksandr T <oleksandr.taras...@outlook.com> Date: Mon, 13 Jan 2025 19:28:46 +0200 Subject: [PATCH 7/8] change release notes --- clang/docs/ReleaseNotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9e5bbbf6dc055a..948ab7271c7ac2 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -764,7 +764,7 @@ Improvements to Clang's diagnostics scope.Unlock(); require(scope); // Warning! Requires mu1. } -- Clang now disallows the use of asterisks preceding constructor and destructor names (#GH121706). +- Diagnose invalid declarators in the declaration of constructors and destructors (#GH121706). Improvements to Clang's time-trace ---------------------------------- >From b3fd9b75907624f321aba24548b3a2f149b3350a Mon Sep 17 00:00:00 2001 From: Oleksandr T <oleksandr.taras...@outlook.com> Date: Mon, 13 Jan 2025 23:56:46 +0200 Subject: [PATCH 8/8] add tests --- clang/test/SemaCXX/conversion-function.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clang/test/SemaCXX/conversion-function.cpp b/clang/test/SemaCXX/conversion-function.cpp index 749e2fc1b452b6..b653a3bf1a1d29 100644 --- a/clang/test/SemaCXX/conversion-function.cpp +++ b/clang/test/SemaCXX/conversion-function.cpp @@ -494,3 +494,10 @@ using Result = B<int>::Lookup<int>; using Result = int (A2<int>::*)(); } #endif + +namespace GH121706 { +struct S { + *operator int(); // expected-error {{cannot specify any part of a return type in the declaration of a conversion function; put the complete type after 'operator'}} + **operator char(); // expected-error {{cannot specify any part of a return type in the declaration of a conversion function; put the complete type after 'operator'}} +}; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits