[cfe-commits] r131338 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp
Sean Hunt
scshunt at csclub.uwaterloo.ca
Fri May 13 22:23:28 PDT 2011
Author: coppro
Date: Sat May 14 00:23:28 2011
New Revision: 131338
URL: http://llvm.org/viewvc/llvm-project?rev=131338&view=rev
Log:
What I hope to be an implementation of defaulted copy assignment
operators.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=131338&r1=131337&r2=131338&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat May 14 00:23:28 2011
@@ -3636,6 +3636,21 @@
def err_defaulted_copy_ctor_const_param : Error<
"the parameter for this explicitly-defaulted copy constructor is const, but "
"a member or base requires it to be non-const">;
+def err_defaulted_copy_assign_params : Error<
+ "an explicitly-defaulted copy assignment operator must have exactly one "
+ "parameter">;
+def err_defaulted_copy_assign_return_type : Error<
+ "an explicitly-defaulted copy assignment operator must return an unqualified "
+ "lvalue reference to its class type">;
+def err_defaulted_copy_assign_volatile_param : Error<
+ "the parameter for an explicitly-defaulted copy assignment operator may not "
+ "be volatile">;
+def err_defaulted_copy_assign_const_param : Error<
+ "the parameter for this explicitly-defaulted copy assignment operator is "
+ "const, but a member or base requires it to be non-const">;
+def err_defaulted_copy_assign_quals : Error<
+ "an explicitly-defaulted copy assignment operator may not have 'const' "
+ "or 'volatile' qualifiers">;
def err_incorrect_defaulted_exception_spec : Error<
"exception specification of explicitly defaulted %select{default constructor|"
"copy constructor|copy assignment operator|destructor}0 does not match the "
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=131338&r1=131337&r2=131338&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sat May 14 00:23:28 2011
@@ -3292,6 +3292,7 @@
void CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record);
void CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *Ctor);
void CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *Ctor);
+ void CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *Method);
void CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *Dtor);
//===--------------------------------------------------------------------===//
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=131338&r1=131337&r2=131338&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat May 14 00:23:28 2011
@@ -3018,10 +3018,11 @@
break;
case CXXCopyAssignment:
- // FIXME: Do copy assignment operators and moves
+ CheckExplicitlyDefaultedCopyAssignment(*MI);
break;
default:
+ // FIXME: Do moves once they exist
llvm_unreachable("non-special member explicitly defaulted!");
}
}
@@ -3064,6 +3065,7 @@
} else if (First) {
// We set the declaration to have the computed exception spec here.
// We know there are no parameters.
+ EPI.ExtInfo = CtorType->getExtInfo();
CD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
}
@@ -3130,6 +3132,7 @@
} else if (First) {
// We set the declaration to have the computed exception spec here.
// We duplicate the one parameter type.
+ EPI.ExtInfo = CtorType->getExtInfo();
CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
}
@@ -3149,6 +3152,88 @@
}
}
+void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) {
+ assert(MD->isExplicitlyDefaulted());
+
+ // Whether this was the first-declared instance of the operator
+ bool First = MD == MD->getCanonicalDecl();
+
+ bool HadError = false;
+ if (MD->getNumParams() != 1) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_params)
+ << MD->getSourceRange();
+ HadError = true;
+ }
+
+ QualType ReturnType =
+ MD->getType()->getAs<FunctionType>()->getResultType();
+ if (!ReturnType->isLValueReferenceType() ||
+ !Context.hasSameType(
+ Context.getCanonicalType(ReturnType->getPointeeType()),
+ Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_return_type);
+ HadError = true;
+ }
+
+ ImplicitExceptionSpecification Spec(Context);
+ bool Const;
+ llvm::tie(Spec, Const) =
+ ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent());
+
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(),
+ *ExceptionType = Context.getFunctionType(
+ Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+
+ // Check for parameter type matching.
+ // This is a copy ctor so we know it's a cv-qualified reference to T.
+ QualType ArgType = OperType->getArgType(0);
+ if (ArgType->getPointeeType().isVolatileQualified()) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_volatile_param);
+ HadError = true;
+ }
+ if (ArgType->getPointeeType().isConstQualified() && !Const) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_const_param);
+ HadError = true;
+ }
+ if (OperType->getTypeQuals()) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_quals);
+ HadError = true;
+ }
+
+ if (OperType->hasExceptionSpec()) {
+ if (CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << 2 /* copy assignment operator */,
+ PDiag(),
+ ExceptionType, SourceLocation(),
+ OperType, MD->getLocation())) {
+ HadError = true;
+ }
+ } else if (First) {
+ // We set the declaration to have the computed exception spec here.
+ // We duplicate the one parameter type.
+ EPI.RefQualifier = OperType->getRefQualifier();
+ EPI.ExtInfo = OperType->getExtInfo();
+ MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI));
+ }
+
+ if (HadError) {
+ MD->setInvalidDecl();
+ return;
+ }
+
+ if (ShouldDeleteCopyAssignmentOperator(MD)) {
+ if (First) {
+ MD->setDeletedAsWritten();
+ } else {
+ Diag(MD->getLocation(), diag::err_out_of_line_default_deletes)
+ << 2 /* copy assignment operator */;
+ MD->setInvalidDecl();
+ }
+ }
+}
+
void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) {
assert(DD->isExplicitlyDefaulted());
@@ -3175,6 +3260,7 @@
} else if (First) {
// We set the declaration to have the computed exception spec here.
// There are no parameters.
+ EPI.ExtInfo = DtorType->getExtInfo();
DD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
}
@@ -3370,9 +3456,12 @@
// Do access control from the constructor
ContextRAII CtorContext(*this, CD);
- bool Union = RD->isUnion();
+ bool Union = RD->isUnion();
- bool ConstArg = CD->getParamDecl(0)->getType().isConstQualified();
+ assert(!CD->getParamDecl(0)->getType()->getPointeeType().isNull() &&
+ "copy assignment arg has no pointee type");
+ bool ConstArg =
+ CD->getParamDecl(0)->getType()->getPointeeType().isConstQualified();
// We do this because we should never actually use an anonymous
// union's constructor.
@@ -3416,8 +3505,6 @@
// Construct a fake expression to perform the copy overloading.
QualType ArgType = BaseType.getUnqualifiedType();
- if (ArgType->isReferenceType())
- ArgType = ArgType->getPointeeType();
if (ConstArg)
ArgType.addConst();
Expr *Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType,
@@ -3457,8 +3544,6 @@
// Construct a fake expression to perform the copy overloading.
QualType ArgType = BaseType.getUnqualifiedType();
- if (ArgType->isReferenceType())
- ArgType = ArgType->getPointeeType();
if (ConstArg)
ArgType.addConst();
Expr *Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType,
@@ -3538,7 +3623,7 @@
QualType ArgType = FieldType;
if (ArgType->isReferenceType())
ArgType = ArgType->getPointeeType();
- if (ConstArg)
+ else if (ConstArg)
ArgType.addConst();
Expr *Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType,
VK_LValue);
@@ -3563,7 +3648,8 @@
bool Union = RD->isUnion();
- bool ConstArg = MD->getParamDecl(0)->getType().isConstQualified();
+ bool ConstArg =
+ MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified();
// We do this because we should never actually use an anonymous
// union's constructor.
@@ -3594,7 +3680,7 @@
// -- a [direct base class] B that cannot be [copied] because overload
// resolution, as applied to B's [copy] assignment operator, results in
- // an ambiguity or a function that is deleted or inaccessibl from the
+ // an ambiguity or a function that is deleted or inaccessible from the
// assignment operator
LookupQualifiedName(R, BaseDecl, false);
@@ -3613,15 +3699,19 @@
// Build a fake argument expression
QualType ArgType = BaseType;
+ QualType ThisType = BaseType;
if (ConstArg)
ArgType.addConst();
- Expr *Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType,
- VK_LValue);
+ Expr *Args[] = { new (Context) OpaqueValueExpr(SourceLocation(), ThisType,
+ VK_LValue)
+ , new (Context) OpaqueValueExpr(SourceLocation(), ArgType,
+ VK_LValue)
+ };
OverloadCandidateSet OCS((SourceLocation()));
OverloadCandidateSet::iterator Best;
- AddFunctionCandidates(R.asUnresolvedSet(), &Arg, 1, OCS);
+ AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
if (OCS.BestViableFunction(*this, SourceLocation(), Best, false) !=
OR_Success)
@@ -3635,31 +3725,44 @@
CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
assert(BaseDecl && "base isn't a CXXRecordDecl");
- /*
// -- a [virtual base class] B that cannot be [copied] because overload
- // resolution, as applied to B's [copy] assignment operator, results in an
- // ambiguity or a function that is deleted or inaccessible from the
- // defaulted assignment operator
- InitializedEntity BaseEntity =
- InitializedEntity::InitializeBase(Context, BI, BI);
- InitializationKind Kind =
- InitializationKind::CreateDirect(SourceLocation(), SourceLocation(),
- SourceLocation());
+ // resolution, as applied to B's [copy] assignment operator, results in
+ // an ambiguity or a function that is deleted or inaccessible from the
+ // assignment operator
- // Construct a fake expression to perform the copy overloading.
- QualType ArgType = BaseType.getUnqualifiedType();
- if (ArgType->isReferenceType())
- ArgType = ArgType->getPointeeType();
+ LookupQualifiedName(R, BaseDecl, false);
+
+ // Filter out any result that isn't a copy-assignment operator.
+ LookupResult::Filter F = R.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isCopyAssignmentOperator())
+ continue;
+
+ F.erase();
+ }
+ F.done();
+
+ // Build a fake argument expression
+ QualType ArgType = BaseType;
+ QualType ThisType = BaseType;
if (ConstArg)
ArgType.addConst();
- Expr *Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType,
- VK_LValue);
+ Expr *Args[] = { new (Context) OpaqueValueExpr(SourceLocation(), ThisType,
+ VK_LValue)
+ , new (Context) OpaqueValueExpr(SourceLocation(), ArgType,
+ VK_LValue)
+ };
- InitializationSequence InitSeq(*this, BaseEntity, Kind, &Arg, 1);
+ OverloadCandidateSet OCS((SourceLocation()));
+ OverloadCandidateSet::iterator Best;
- if (InitSeq.getKind() == InitializationSequence::FailedSequence)
+ AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
+
+ if (OCS.BestViableFunction(*this, SourceLocation(), Best, false) !=
+ OR_Success)
return true;
- */
}
for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
@@ -3704,36 +3807,41 @@
} else if (Union && !FieldRecord->hasTrivialCopyAssignment()) {
return true;
}
- }
- /*
- llvm::SmallVector<InitializedEntity, 4> Entities;
- QualType CurType = FI->getType();
- Entities.push_back(InitializedEntity::InitializeMember(*FI, 0));
- while (CurType->isArrayType()) {
- Entities.push_back(InitializedEntity::InitializeElement(Context, 0,
- Entities.back()));
- CurType = Context.getAsArrayType(CurType)->getElementType();
- }
+ LookupQualifiedName(R, FieldRecord, false);
- InitializationKind Kind =
- InitializationKind::CreateDirect(SourceLocation(), SourceLocation(),
- SourceLocation());
-
- // Construct a fake expression to perform the copy overloading.
- QualType ArgType = FieldType;
- if (ArgType->isReferenceType())
- ArgType = ArgType->getPointeeType();
- if (ConstArg)
- ArgType.addConst();
- Expr *Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType,
- VK_LValue);
+ // Filter out any result that isn't a copy-assignment operator.
+ LookupResult::Filter F = R.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isCopyAssignmentOperator())
+ continue;
+
+ F.erase();
+ }
+ F.done();
- InitializationSequence InitSeq(*this, Entities.back(), Kind, &Arg, 1);
+ // Build a fake argument expression
+ QualType ArgType = FieldType;
+ QualType ThisType = FieldType;
+ if (ConstArg)
+ ArgType.addConst();
+ Expr *Args[] = { new (Context) OpaqueValueExpr(SourceLocation(), ThisType,
+ VK_LValue)
+ , new (Context) OpaqueValueExpr(SourceLocation(), ArgType,
+ VK_LValue)
+ };
- if (InitSeq.getKind() == InitializationSequence::FailedSequence)
- return true;
- */
+ OverloadCandidateSet OCS((SourceLocation()));
+ OverloadCandidateSet::iterator Best;
+
+ AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
+
+ if (OCS.BestViableFunction(*this, SourceLocation(), Best, false) !=
+ OR_Success)
+ return true;
+ }
}
return false;
@@ -8539,6 +8647,13 @@
break;
}
+ case CXXCopyAssignment: {
+ CheckExplicitlyDefaultedCopyAssignment(MD);
+ if (!MD->isInvalidDecl())
+ DefineImplicitCopyAssignment(DefaultLoc, MD);
+ break;
+ }
+
case CXXDestructor: {
CXXDestructorDecl *DD = cast<CXXDestructorDecl>(MD);
CheckExplicitlyDefaultedDestructor(DD);
@@ -8548,7 +8663,7 @@
}
default:
- // FIXME: Do the rest once we have functions
+ // FIXME: Do the rest once we have move functions
break;
}
} else {
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=131338&r1=131337&r2=131338&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sat May 14 00:23:28 2011
@@ -9870,7 +9870,7 @@
if (Destructor->isVirtual())
MarkVTableUsed(Loc, Destructor->getParent());
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
- if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
+ if (MethodDecl->isDefaulted() && MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
if (!MethodDecl->isUsed(false))
DefineImplicitCopyAssignment(Loc, MethodDecl);
More information about the cfe-commits
mailing list