Skip to content

[clang] Mark constructors with invalid initializers as invalid #137773

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
4 changes: 3 additions & 1 deletion clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4064,8 +4064,10 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
if (!MemInit.isInvalid())
MemInitializers.push_back(MemInit.get());
else
else {
ConstructorDecl->setInvalidDecl();
AnyErrors = true;
}

if (Tok.is(tok::comma))
ConsumeToken();
Expand Down
12 changes: 5 additions & 7 deletions clang/test/AST/ByteCode/constexpr-subobj-initialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,27 @@ struct DelBase {
constexpr DelBase() = delete; // expected-note {{'DelBase' has been explicitly marked deleted here}}
};

struct Foo : DelBase { // expected-note 2{{constructor of base class 'baseclass_uninit::DelBase' is not called}}
struct Foo : DelBase { // expected-note-re 2{{constructor of base class '{{.*}}DelBase' is not called}}
constexpr Foo() {}; // expected-error {{call to deleted constructor of 'DelBase'}}
};
constexpr Foo f; // expected-error {{must be initialized by a constant expression}}

struct Bar : Foo {
constexpr Bar() {};
};
constexpr Bar bar; // expected-error {{must be initialized by a constant expression}}

struct Base {};
struct A : Base { // expected-note {{constructor of base class 'baseclass_uninit::Base' is not called}}
struct A : Base { // expected-note 2{{candidate constructor}}
constexpr A() : value() {} // expected-error {{member initializer 'value' does not name a non-static data member or base class}}
};

constexpr A a; // expected-error {{must be initialized by a constant expression}}

constexpr A a; // expected-error {{no matching constructor}}

struct B : Base { // expected-note {{constructor of base class 'baseclass_uninit::Base' is not called}}
struct B : Base { // expected-note 2{{candidate constructor}}
constexpr B() : {} // expected-error {{expected class member or base class name}}
};

constexpr B b; // expected-error {{must be initialized by a constant expression}}
constexpr B b; // expected-error {{no matching constructor}}
} // namespace baseclass_uninit


Expand Down
2 changes: 1 addition & 1 deletion clang/test/SemaCXX/class-base-member-init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ namespace test5 {
decltype(Base(1))(2), // expected-error {{multiple initializations given for base 'decltype(Base(1))' (aka 'test5::Base')}}
decltype(int())() { // expected-error {{constructor initializer 'decltype(int())' (aka 'int') does not name a class}}
}
A(float) : decltype(A())(3) {
A(float) : decltype(A())(3) { // expected-error {{constructor for 'A' creates a delegation cycle}}
}
};
}
Expand Down
4 changes: 2 additions & 2 deletions clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,9 +535,9 @@ namespace InvalidBaseClass {
};

class InBetween : public F{};
class E : public InBetween {
class E : public InBetween { // expected-note 2{{candidate constructor}}
public:
constexpr E() : F{3} {} // expected-error {{not a direct or virtual base}}
};
static_assert(__builtin_bit_cast(char, E()) == 0); // expected-error {{not an integral constant expression}}
static_assert(__builtin_bit_cast(char, E()) == 0); // expected-error {{no matching constructor}}
}
8 changes: 4 additions & 4 deletions clang/test/SemaCXX/constexpr-subobj-initialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ struct Bar : Foo {
constexpr Bar bar; // expected-error {{must be initialized by a constant expression}}

struct Base {};
struct A : Base { // expected-note-re {{constructor of base class '{{.*}}Base' is not called}}
struct A : Base { // expected-note 2{{candidate constructor}}
constexpr A() : value() {} // expected-error {{member initializer 'value' does not name a non-static data member or base class}}
};

constexpr A a; // expected-error {{must be initialized by a constant expression}}
constexpr A a; // expected-error {{no matching constructor}}

struct B : Base { // expected-note-re {{constructor of base class '{{.*}}Base' is not called}}
struct B : Base { // expected-note 2{{candidate constructor}}
constexpr B() : {} // expected-error {{expected class member or base class name}}
};

constexpr B b; // expected-error {{must be initialized by a constant expression}}
constexpr B b; // expected-error {{no matching constructor}}
} // namespace baseclass_uninit


Expand Down
10 changes: 7 additions & 3 deletions clang/test/SemaCXX/constructor-initializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@
// RUN: %clang_cc1 -Wreorder -fsyntax-only -verify -std=c++98 %s
// RUN: %clang_cc1 -Wreorder -fsyntax-only -verify -std=c++11 %s

class A {
class A {
// expected-note@-1 {{candidate constructor}}
#if __cplusplus >= 201103L // C++11 or later
// expected-note@-3 {{candidate constructor}}
#endif
int m;
public:
A() : A::m(17) { } // expected-error {{member initializer 'm' does not name a non-static data member or base class}}
A(int);
A(int); // expected-note {{candidate constructor}}
};

class B : public A {
public:
B() : A(), m(1), n(3.14) { }
B() : A(), m(1), n(3.14) { } // expected-error {{no matching constructor for initialization of 'A'}}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't seem like an improvement. Is there some way we can recover more gracefully for constructors with a valid signature?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oof, yeah, this diagnostic is confusing because it sure looks like there's a matching constructor for A.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess not, unless invalid constructors were to take part in lookup later when calling A().


private:
int m;
Expand Down