Skip to content
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

[Clang] disallow the use of asterisks preceding constructor and destructor names #122621

Merged
merged 11 commits into from
Jan 16, 2025
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,7 @@ Improvements to Clang's diagnostics
scope.Unlock();
require(scope); // Warning! Requires mu1.
}
- Diagnose invalid declarators in the declaration of constructors and destructors (#GH121706).

Improvements to Clang's time-trace
----------------------------------
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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_ctor_dtor_decl : Error<
"invalid %select{constructor|destructor}0 declaration">;

def err_constructor_return_type : Error<
"constructor cannot have a return type">;
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10757,6 +10757,22 @@ static void checkMethodTypeQualifiers(Sema &S, Declarator &D, unsigned DiagID) {
}
}

static void diagnoseInvalidDeclaratorChunks(Sema &S, Declarator &D,
unsigned Kind) {
if (D.isInvalidType() || D.getNumTypeObjects() <= 1)
return;

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, diag::err_invalid_ctor_dtor_decl)
<< Kind << Chunk.getSourceRange();
D.setInvalidType();
}

QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
StorageClass &SC) {
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
Expand Down Expand Up @@ -10792,6 +10808,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
}

checkMethodTypeQualifiers(*this, D, diag::err_invalid_qualified_constructor);
diagnoseInvalidDeclaratorChunks(*this, D, /*constructor*/ 0);

// C++0x [class.ctor]p4:
// A constructor shall not be declared with a ref-qualifier.
Expand Down Expand Up @@ -10958,6 +10975,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
}

checkMethodTypeQualifiers(*this, D, diag::err_invalid_qualified_destructor);
diagnoseInvalidDeclaratorChunks(*this, D, /*destructor*/ 1);

// C++0x [class.dtor]p2:
// A destructor shall not be declared with a ref-qualifier.
Expand Down
77 changes: 77 additions & 0 deletions clang/test/SemaCXX/constructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,80 @@ 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 {
a-tarasyuk marked this conversation as resolved.
Show resolved Hide resolved

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}}
};

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();
};

}
7 changes: 7 additions & 0 deletions clang/test/SemaCXX/conversion-function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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'}}
};
}
46 changes: 46 additions & 0 deletions clang/test/SemaCXX/destructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,4 +586,50 @@ 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 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}}
};
}

#endif // BE_THE_HEADER
Loading