During codegen assert that any copy assignment, destructor or constructor that

we need to synthesize has been marked as used by Sema.

Change Sema to avoid these asserts.

llvm-svn: 97589
This commit is contained in:
Rafael Espindola 2010-03-02 21:28:26 +00:00
parent f61e34d120
commit 70e040d552
5 changed files with 103 additions and 53 deletions

View File

@ -752,14 +752,20 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
// A called constructor which has no definition or declaration need be
// synthesized.
else if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
if (CD->isImplicit())
if (CD->isImplicit()) {
assert (CD->isUsed());
DeferredDeclsToEmit.push_back(D);
}
} else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) {
if (DD->isImplicit())
if (DD->isImplicit()) {
assert (DD->isUsed());
DeferredDeclsToEmit.push_back(D);
}
} else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
if (MD->isCopyAssignment() && MD->isImplicit())
if (MD->isCopyAssignment() && MD->isImplicit()) {
assert (MD->isUsed());
DeferredDeclsToEmit.push_back(D);
}
}
}

View File

@ -1638,8 +1638,22 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
new (Context) CXXBaseOrMemberInitializer*[NumInitializers];
Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers);
for (unsigned Idx = 0; Idx < NumInitializers; ++Idx)
baseOrMemberInitializers[Idx] = AllToInit[Idx];
for (unsigned Idx = 0; Idx < NumInitializers; ++Idx) {
CXXBaseOrMemberInitializer *Member = AllToInit[Idx];
baseOrMemberInitializers[Idx] = Member;
if (!Member->isBaseInitializer())
continue;
const Type *BaseType = Member->getBaseClass();
const RecordType *RT = BaseType->getAs<RecordType>();
if (!RT)
continue;
CXXRecordDecl *BaseClassDecl =
cast<CXXRecordDecl>(RT->getDecl());
if (BaseClassDecl->hasTrivialDestructor())
continue;
CXXDestructorDecl *DD = BaseClassDecl->getDestructor(Context);
MarkDeclarationReferenced(Constructor->getLocation(), DD);
}
}
return HadError;
@ -5791,55 +5805,74 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
return Dcl;
}
void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
CXXMethodDecl *MD) {
static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) {
// Ignore dependent types.
if (MD->isDependentContext())
return;
CXXRecordDecl *RD = MD->getParent();
// Ignore classes without a vtable.
if (!RD->isDynamicClass())
return;
return false;
// Ignore declarations that are not definitions.
if (!MD->isThisDeclarationADefinition())
return;
if (isa<CXXConstructorDecl>(MD)) {
switch (MD->getParent()->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
// Classes that aren't instantiations of templates don't need their
// virtual methods marked until we see the definition of the key
// function.
return;
case TSK_ImplicitInstantiation:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
// This is a constructor of a class template; mark all of the virtual
// members as referenced to ensure that they get instantiatied.
break;
}
} else if (!MD->isOutOfLine()) {
// Consider only out-of-line definitions of member functions. When we see
// an inline definition, it's too early to compute the key function.
return;
} else if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD)) {
// If this is not the key function, we don't need to mark virtual members.
if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
return;
} else {
// The class has no key function, so we've already noted that we need to
// mark the virtual members of this class.
return;
return false;
CXXRecordDecl *RD = MD->getParent();
// Ignore classes without a vtable.
if (!RD->isDynamicClass())
return false;
switch (MD->getParent()->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
// Classes that aren't instantiations of templates don't need their
// virtual methods marked until we see the definition of the key
// function.
break;
case TSK_ImplicitInstantiation:
// This is a constructor of a class template; mark all of the virtual
// members as referenced to ensure that they get instantiatied.
if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
return true;
break;
case TSK_ExplicitInstantiationDeclaration:
return true; //FIXME: This looks wrong.
case TSK_ExplicitInstantiationDefinition:
// This is method of a explicit instantiation; mark all of the virtual
// members as referenced to ensure that they get instantiatied.
return true;
}
// Consider only out-of-line definitions of member functions. When we see
// an inline definition, it's too early to compute the key function.
if (!MD->isOutOfLine())
return false;
const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
// If there is no key function, we will need a copy of the vtable.
if (!KeyFunction)
return true;
// If this is the key function, we need to mark virtual members.
if (KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl())
return true;
return false;
}
void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
CXXMethodDecl *MD) {
CXXRecordDecl *RD = MD->getParent();
// We will need to mark all of the virtual members as referenced to build the
// vtable.
ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc));
// We actually call MarkVirtualMembersReferenced instead of adding to
// ClassesWithUnmarkedVirtualMembers because this marking is needed by
// codegen that will happend before we finish parsing the file.
if (needsVtable(MD, Context))
MarkVirtualMembersReferenced(Loc, RD);
}
bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() {
@ -5867,4 +5900,3 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) {
MarkDeclarationReferenced(Loc, MD);
}
}

View File

@ -426,6 +426,18 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
: diag::err_throw_incomplete)
<< E->getSourceRange()))
return true;
// FIXME: This is just a hack to mark the copy constructor referenced.
// This should go away when the next FIXME is fixed.
const RecordType *RT = Ty->getAs<RecordType>();
if (!RT)
return false;
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->hasTrivialCopyConstructor())
return false;
CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(Context, 0);
MarkDeclarationReferenced(ThrowLoc, CopyCtor);
}
// FIXME: Construct a temporary here.

View File

@ -15,9 +15,9 @@ void B::f() { // expected-note {{implicit default destructor for 'struct B' firs
struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}}
C();
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
}; // expected-note {{implicit default destructor for 'struct C' first required here}}
};
C::C() { }
C::C() { } // expected-note {{implicit default destructor for 'struct C' first required here}}
struct D : A { // expected-error {{no suitable member 'operator delete' in 'D'}}
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}

View File

@ -14,7 +14,7 @@ template<class T> int A<T>::a(T x) {
}
void f(A<int> x) {
x.anchor();
x.anchor(); // expected-note{{in instantiation of member function 'PR5557::A<int>::anchor' requested here}}
}
template<typename T>
@ -36,10 +36,10 @@ struct Base {
template<typename T>
struct Derived : Base<T> {
virtual void foo() { }
virtual void foo() { } // expected-note {{in instantiation of member function 'Base<int>::~Base' requested here}}
};
template struct Derived<int>; // expected-note{{instantiation}}
template struct Derived<int>;
template<typename T>
struct HasOutOfLineKey {
@ -52,4 +52,4 @@ T *HasOutOfLineKey<T>::f(float *fp) {
return fp; // expected-error{{cannot initialize return object of type 'int *' with an lvalue of type 'float *'}}
}
HasOutOfLineKey<int> out_of_line;
HasOutOfLineKey<int> out_of_line; // expected-note{{in instantiation of member function 'HasOutOfLineKey<int>::HasOutOfLineKey' requested here}}