aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-05-12 16:39:35 +0000
committerDouglas Gregor <dgregor@apple.com>2010-05-12 16:39:35 +0000
commitc63d2c8469d6b96712b324f76b4af07e1852313f (patch)
tree5dadce03297f0232292d330f080f6b9346b1c1be
parenta9f1bb19f75871481aa66316902bb10f4669e596 (diff)
When we emit an error during the implicit definition of a special
member function (default constructor, copy constructor, copy assignment operator, destructor), emit a note showing where that implicit definition was required. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103619 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/Sema.h18
-rw-r--r--lib/Sema/SemaDeclCXX.cpp28
-rw-r--r--test/CXX/class.access/p4.cpp20
-rw-r--r--test/SemaCXX/default-assignment-operator.cpp3
4 files changed, 54 insertions, 15 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index fa8976fdc4..70e445ffae 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -3572,6 +3572,24 @@ public:
}
};
+ /// \brief RAII class that determines when any errors have occurred
+ /// between the time the instance was created and the time it was
+ /// queried.
+ class ErrorTrap {
+ Sema &SemaRef;
+ unsigned PrevErrors;
+
+ public:
+ explicit ErrorTrap(Sema &SemaRef)
+ : SemaRef(SemaRef), PrevErrors(SemaRef.getDiagnostics().getNumErrors()) {}
+
+ /// \brief Determine whether any errors have occurred since this
+ /// object instance was created.
+ bool hasErrorOccurred() const {
+ return SemaRef.getDiagnostics().getNumErrors() > PrevErrors;
+ }
+ };
+
/// \brief A stack-allocated class that identifies which local
/// variable declaration instantiations are present in this scope.
///
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 72a57c36bb..7320bc6b04 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -4146,12 +4146,15 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
ImplicitlyDefinedFunctionScope Scope(*this, Constructor);
- if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) {
+ ErrorTrap Trap(*this);
+ if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false) ||
+ Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
} else {
Constructor->setUsed();
+ MaybeMarkVirtualMembersReferenced(CurrentLocation, Constructor);
}
}
@@ -4162,14 +4165,16 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
+ if (Destructor->isInvalidDecl())
+ return;
+
ImplicitlyDefinedFunctionScope Scope(*this, Destructor);
+ ErrorTrap Trap(*this);
MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
Destructor->getParent());
- // FIXME: If CheckDestructor fails, we should emit a note about where the
- // implicit destructor was needed.
- if (CheckDestructor(Destructor)) {
+ if (CheckDestructor(Destructor) || Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXDestructor << Context.getTagDeclType(ClassDecl);
@@ -4178,6 +4183,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
}
Destructor->setUsed();
+ MaybeMarkVirtualMembersReferenced(CurrentLocation, Destructor);
}
/// \brief Builds a statement that copies the given entity from \p From to
@@ -4396,6 +4402,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CopyAssignOperator->setUsed();
ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator);
+ ErrorTrap Trap(*this);
// C++0x [class.copy]p30:
// The implicitly-defined or explicitly-defaulted copy assignment operator
@@ -4616,6 +4623,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Invalid = true;
else {
Statements.push_back(Return.takeAs<Stmt>());
+
+ if (Trap.hasErrorOccurred()) {
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
+ Invalid = true;
+ }
}
}
@@ -4628,6 +4641,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
/*isStmtExpr=*/false);
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
CopyAssignOperator->setBody(Body.takeAs<Stmt>());
+
+ MaybeMarkVirtualMembersReferenced(CurrentLocation, CopyAssignOperator);
}
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
@@ -4642,8 +4657,10 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor);
+ ErrorTrap Trap(*this);
- if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false)) {
+ if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false) ||
+ Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
CopyConstructor->setInvalidDecl();
@@ -4653,6 +4670,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
MultiStmtArg(*this, 0, 0),
/*isStmtExpr=*/false)
.takeAs<Stmt>());
+ MaybeMarkVirtualMembersReferenced(CurrentLocation, CopyConstructor);
}
CopyConstructor->setUsed();
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index 1cd8966136..e8afbe7a39 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -97,7 +97,7 @@ namespace test2 {
A A::foo; // okay
class B : A { }; // expected-error {{base class 'test2::A' has private constructor}}
- B b;
+ B b; // expected-note{{implicit default constructor}}
class C : virtual A {
public:
@@ -105,7 +105,7 @@ namespace test2 {
};
class D : C { }; // expected-error {{inherited virtual base class 'test2::A' has private constructor}}
- D d;
+ D d; // expected-note{{implicit default constructor}}
}
// Implicit destructor calls.
@@ -143,13 +143,15 @@ namespace test3 {
};
class Derived3 : // expected-error 2 {{inherited virtual base class 'Base<2>' has private destructor}} \
- // expected-error 2 {{inherited virtual base class 'Base<3>' has private destructor}}
+ // expected-error 2 {{inherited virtual base class 'Base<3>' has private destructor}} \
+ // expected-note 2{{implicit default constructor}}
Base<0>, // expected-error 2 {{base class 'Base<0>' has private destructor}}
virtual Base<1>, // expected-error 2 {{base class 'Base<1>' has private destructor}}
Base2, // expected-error 2 {{base class 'test3::Base2' has private destructor}}
virtual Base3
- {};
- Derived3 d3;
+ {};
+ Derived3 d3; // expected-note {{implicit default constructor}}\
+ // expected-note{{implicit default destructor}}}
}
// Conversion functions.
@@ -205,13 +207,13 @@ namespace test5 {
class Test1 { A a; }; // expected-error {{private member}}
void test1() {
Test1 a;
- a = Test1();
+ a = Test1(); // expected-note{{implicit default copy}}
}
class Test2 : A {}; // expected-error {{private member}}
void test2() {
Test2 a;
- a = Test2();
+ a = Test2(); // expected-note{{implicit default copy}}
}
}
@@ -224,12 +226,12 @@ namespace test6 {
class Test1 { A a; }; // expected-error {{field of type 'test6::A' has private copy constructor}}
void test1(const Test1 &t) {
- Test1 a = t;
+ Test1 a = t; // expected-note{{implicit default copy}}
}
class Test2 : A {}; // expected-error {{base class 'test6::A' has private copy constructor}}
void test2(const Test2 &t) {
- Test2 a = t;
+ Test2 a = t; // expected-note{{implicit default copy}}
}
}
diff --git a/test/SemaCXX/default-assignment-operator.cpp b/test/SemaCXX/default-assignment-operator.cpp
index 4b5531e0c8..668c600366 100644
--- a/test/SemaCXX/default-assignment-operator.cpp
+++ b/test/SemaCXX/default-assignment-operator.cpp
@@ -101,7 +101,8 @@ namespace ProtectedCheck {
X x;
};
- void f(Z z) { z = z; } //
+ void f(Z z) { z = z; } // expected-note{{implicit default copy assignment operator}}
+
}
namespace MultiplePaths {