More toward synthesizing copy assignments. SWIP.
llvm-svn: 78861
This commit is contained in:
parent
c4c3c66ff3
commit
bbd5e8c2cf
@ -493,7 +493,9 @@ public:
|
||||
|
||||
/// hasConstCopyAssignment - Determines whether this class has a
|
||||
/// copy assignment operator that accepts a const-qualified argument.
|
||||
bool hasConstCopyAssignment(ASTContext &Context) const;
|
||||
/// It returns its decl in MD if found.
|
||||
bool hasConstCopyAssignment(ASTContext &Context,
|
||||
const CXXMethodDecl *&MD) const;
|
||||
|
||||
/// addedConstructor - Notify the class that another constructor has
|
||||
/// been added. This routine helps maintain information about the
|
||||
|
||||
@ -168,7 +168,8 @@ CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context,
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const {
|
||||
bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context,
|
||||
const CXXMethodDecl *& MD) const {
|
||||
QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
|
||||
const_cast<CXXRecordDecl*>(this)));
|
||||
DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal);
|
||||
@ -200,7 +201,7 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const {
|
||||
}
|
||||
if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType)
|
||||
continue;
|
||||
|
||||
MD = Method;
|
||||
// We have a single argument of type cv X or cv X&, i.e. we've found the
|
||||
// copy assignment operator. Return whether it accepts const arguments.
|
||||
return AcceptsConst;
|
||||
|
||||
@ -822,6 +822,46 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
|
||||
}
|
||||
}
|
||||
|
||||
/// EmitClassCopyAssignment - This routine generates code to copy assign a class
|
||||
/// object from SrcValue to DestValue. Assignment can be either a bitwise
|
||||
/// assignment of via an assignment operator call.
|
||||
void CodeGenFunction::EmitClassCopyAssignment(
|
||||
llvm::Value *Dest, llvm::Value *Src,
|
||||
const CXXRecordDecl *ClassDecl,
|
||||
const CXXRecordDecl *BaseClassDecl,
|
||||
QualType Ty) {
|
||||
if (ClassDecl) {
|
||||
Dest = AddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl);
|
||||
Src = AddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl) ;
|
||||
}
|
||||
if (BaseClassDecl->hasTrivialCopyAssignment()) {
|
||||
EmitAggregateCopy(Dest, Src, Ty);
|
||||
return;
|
||||
}
|
||||
|
||||
const CXXMethodDecl *MD = 0;
|
||||
if (BaseClassDecl->hasConstCopyAssignment(getContext(), MD)) {
|
||||
const FunctionProtoType *FPT = MD->getType()->getAsFunctionProtoType();
|
||||
const llvm::Type *Ty =
|
||||
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
|
||||
FPT->isVariadic());
|
||||
llvm::Constant *Callee = CGM.GetAddrOfFunction(GlobalDecl(MD), Ty);
|
||||
|
||||
CallArgList CallArgs;
|
||||
// Push the this (Dest) ptr.
|
||||
CallArgs.push_back(std::make_pair(RValue::get(Dest),
|
||||
MD->getThisType(getContext())));
|
||||
|
||||
// Push the Src ptr.
|
||||
CallArgs.push_back(std::make_pair(RValue::get(Src),
|
||||
MD->getParamDecl(0)->getType()));
|
||||
QualType ResultType =
|
||||
MD->getType()->getAsFunctionType()->getResultType();
|
||||
EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
|
||||
Callee, CallArgs, MD);
|
||||
}
|
||||
}
|
||||
|
||||
/// SynthesizeDefaultConstructor - synthesize a default constructor
|
||||
void
|
||||
CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *CD,
|
||||
@ -916,19 +956,71 @@ void CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *CD,
|
||||
/// the base-specifier-list, and then the immediate nonstatic data members of X
|
||||
/// are assigned, in the order in which they were declared in the class
|
||||
/// definition.Each subobject is assigned in the manner appropriate to its type:
|
||||
/// — if the subobject is of class type, the copy assignment operator for the
|
||||
/// class is used (as if by explicit qual- ification; that is, ignoring any
|
||||
/// if the subobject is of class type, the copy assignment operator for the
|
||||
/// class is used (as if by explicit qualification; that is, ignoring any
|
||||
/// possible virtual overriding functions in more derived classes);
|
||||
/// — if the subobject is an array, each element is assigned, in the manner
|
||||
///
|
||||
/// if the subobject is an array, each element is assigned, in the manner
|
||||
/// appropriate to the element type;
|
||||
/// — if the subobject is of scalar type, the built-in assignment operator is
|
||||
///
|
||||
/// if the subobject is of scalar type, the built-in assignment operator is
|
||||
/// used.
|
||||
void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD,
|
||||
const FunctionDecl *FD,
|
||||
llvm::Function *Fn,
|
||||
const FunctionArgList &Args) {
|
||||
|
||||
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
|
||||
assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
|
||||
"SynthesizeCXXCopyAssignment - copy assignment has user declaration");
|
||||
StartFunction(FD, FD->getResultType(), Fn, Args, SourceLocation());
|
||||
|
||||
FunctionArgList::const_iterator i = Args.begin();
|
||||
const VarDecl *ThisArg = i->first;
|
||||
llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg);
|
||||
llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this");
|
||||
const VarDecl *SrcArg = (i+1)->first;
|
||||
llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg);
|
||||
llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj);
|
||||
|
||||
for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
|
||||
Base != ClassDecl->bases_end(); ++Base) {
|
||||
// FIXME. copy assignment of virtual base NYI
|
||||
if (Base->isVirtual())
|
||||
continue;
|
||||
|
||||
CXXRecordDecl *BaseClassDecl
|
||||
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||
EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl,
|
||||
Base->getType());
|
||||
}
|
||||
|
||||
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
|
||||
FieldEnd = ClassDecl->field_end();
|
||||
Field != FieldEnd; ++Field) {
|
||||
QualType FieldType = getContext().getCanonicalType((*Field)->getType());
|
||||
|
||||
// FIXME. How about copy assignment of arrays!
|
||||
assert(!getContext().getAsArrayType(FieldType) &&
|
||||
"FIXME. Copy assignment of arrays NYI");
|
||||
|
||||
if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
|
||||
CXXRecordDecl *FieldClassDecl
|
||||
= cast<CXXRecordDecl>(FieldClassType->getDecl());
|
||||
LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
|
||||
LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
|
||||
|
||||
EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(),
|
||||
0 /*ClassDecl*/, FieldClassDecl, FieldType);
|
||||
continue;
|
||||
}
|
||||
// Do a built-in assignment of scalar data members.
|
||||
LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
|
||||
LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
|
||||
RValue RVRHS = EmitLoadOfLValue(RHS, FieldType);
|
||||
EmitStoreThroughLValue(RVRHS, LHS, FieldType);
|
||||
}
|
||||
|
||||
FinishFunction();
|
||||
}
|
||||
|
||||
|
||||
@ -575,6 +575,11 @@ public:
|
||||
const CXXRecordDecl *BaseClassDecl,
|
||||
QualType Ty);
|
||||
|
||||
void EmitClassCopyAssignment(llvm::Value *DestValue, llvm::Value *SrcValue,
|
||||
const CXXRecordDecl *ClassDecl,
|
||||
const CXXRecordDecl *BaseClassDecl,
|
||||
QualType Ty);
|
||||
|
||||
void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
|
||||
llvm::Value *This,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
|
||||
@ -1398,7 +1398,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
||||
HasConstCopyAssignment && Base != ClassDecl->bases_end(); ++Base) {
|
||||
const CXXRecordDecl *BaseClassDecl
|
||||
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||
HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context);
|
||||
const CXXMethodDecl *MD = 0;
|
||||
HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context,
|
||||
MD);
|
||||
}
|
||||
|
||||
// -- for all the nonstatic data members of X that are of a class
|
||||
@ -1414,8 +1416,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
||||
if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
|
||||
const CXXRecordDecl *FieldClassDecl
|
||||
= cast<CXXRecordDecl>(FieldClassType->getDecl());
|
||||
const CXXMethodDecl *MD = 0;
|
||||
HasConstCopyAssignment
|
||||
= FieldClassDecl->hasConstCopyAssignment(Context);
|
||||
= FieldClassDecl->hasConstCopyAssignment(Context, MD);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user