[cfe-commits] r138821 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ lib/AST/ lib/CodeGen/ lib/Sema/ test/CXX/dcl.decl/dcl.init/ test/CXX/special/class.copy/ test/CXX/special/class.inhctor/ test/CXX/stmt.stmt/stmt.iter/stmt.ranged/ test/CXX/temp/temp.decls/temp.variadic/ test/SemaCXX/
Sebastian Redl
sebastian.redl at getdesigned.at
Wed Aug 31 04:20:48 PDT 2011
On 30.08.2011, at 23:06, Douglas Gregor wrote:
>
> On Aug 30, 2011, at 12:58 PM, Sebastian Redl wrote:
>
>> Author: cornedbee
>> Date: Tue Aug 30 14:58:05 2011
>> New Revision: 138821
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=138821&view=rev
>> Log:
>> Declare and define implicit move constructor and assignment operator.
>>
>> This makes the code duplication of implicit special member handling even worse,
>> but the cleanup will have to come later. For now, this works.
>> Follow-up with tests for explicit defaulting and enabling the __has_feature
>> flag to come.
>
> Awesome!
>
>>
>> Modified: cfe/trunk/include/clang/AST/DeclCXX.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=138821&r1=138820&r2=138821&view=diff
>> ==============================================================================
>> --- cfe/trunk/include/clang/AST/DeclCXX.h (original)
>> +++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Aug 30 14:58:05 2011
>> @@ -468,6 +468,14 @@
>> /// \brief Whether we have already declared a destructor within the class.
>> bool DeclaredDestructor : 1;
>>
>> + /// \brief Whether an implicit move constructor was attempted to be declared
>> + /// but would have been deleted.
>> + bool FailedImplicitMoveConstructor : 1;
>> +
>> + /// \brief Whether an implicit move assignment operator was attempted to be
>> + /// declared but would have been deleted.
>> + bool FailedImplicitMoveAssignment : 1;
>
> These bits aren't serialized to the AST file?
>
Ah, not yet. Good catch. I'm rusty ...
>> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=138821&r1=138820&r2=138821&view=diff
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Aug 30 14:58:05 2011
>> @@ -1860,6 +1860,19 @@
>> EllipsisLoc);
>> }
>>
>> +// Create a static_cast\<T&&>(expr).
>> +static Expr *CastForMoving(Sema &SemaRef, Expr *E) {
>> + QualType ExprType = E->getType();
>> + QualType TargetType = SemaRef.Context.getRValueReferenceType(ExprType);
>> + SourceLocation ExprLoc = E->getLocStart();
>> + TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo(
>> + TargetType, ExprLoc);
>> +
>> + return SemaRef.BuildCXXNamedCast(ExprLoc, tok::kw_static_cast, TargetLoc, E,
>> + SourceRange(ExprLoc, ExprLoc),
>> + E->getSourceRange()).take();
>> +}
>> +
>> /// ImplicitInitializerKind - How an implicit base or member initializer should
>> /// initialize its base or member.
>> enum ImplicitInitializerKind {
>> @@ -1890,7 +1903,9 @@
>> break;
>> }
>>
>> + case IIK_Move:
>> case IIK_Copy: {
>> + bool Moving = ImplicitInitKind == IIK_Move;
>> ParmVarDecl *Param = Constructor->getParamDecl(0);
>> QualType ParamType = Param->getType().getNonReferenceType();
>>
>> @@ -1898,17 +1913,22 @@
>> DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param,
>> Constructor->getLocation(), ParamType,
>> VK_LValue, 0);
>> -
>> +
>> // Cast to the base class to avoid ambiguities.
>> QualType ArgTy =
>> SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(),
>> ParamType.getQualifiers());
>>
>> + if (Moving) {
>> + CopyCtorArg = CastForMoving(SemaRef, CopyCtorArg);
>> + }
>> +
>> CXXCastPath BasePath;
>> BasePath.push_back(BaseSpec);
>> CopyCtorArg = SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy,
>> CK_UncheckedDerivedToBase,
>> - VK_LValue, &BasePath).take();
>> + Moving ? VK_RValue : VK_LValue,
>> + &BasePath).take();
>
> Shouldn't this be VK_XValue rather than VK_RValue?
>
Yes.
>>
>> @@ -1964,11 +1987,16 @@
>> DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param,
>> Loc, ParamType, VK_LValue, 0);
>>
>> + if (Moving) {
>> + MemberExprBase = CastForMoving(SemaRef, MemberExprBase);
>> + }
>> +
>> // Build a reference to this field within the parameter.
>> CXXScopeSpec SS;
>> LookupResult MemberLookup(SemaRef, Field->getDeclName(), Loc,
>> Sema::LookupMemberName);
>> - MemberLookup.addDecl(Indirect? cast<ValueDecl>(Indirect) : cast<ValueDecl>(Field), AS_public);
>> + MemberLookup.addDecl(Indirect ? cast<ValueDecl>(Indirect)
>> + : cast<ValueDecl>(Field), AS_public);
>> MemberLookup.resolveKind();
>> ExprResult CopyCtorArg
>> = SemaRef.BuildMemberReferenceExpr(MemberExprBase,
>> @@ -1980,7 +2008,14 @@
>> /*TemplateArgs=*/0);
>> if (CopyCtorArg.isInvalid())
>> return true;
>> -
>> +
>> + // C++11 [class.copy]p15:
>> + // - if a member m has rvalue reference type T&&, it is direct-initialized
>> + // with static_cast<T&&>(x.m);
>> + if (RefersToRValueRef(CopyCtorArg.get())) {
>> + CopyCtorArg = CastForMoving(SemaRef, CopyCtorArg.take());
>> + }
>
> The name "CopyCtorArg" starts to lose some meaning hereā¦
>
True, I just didn't want to clutter the patch with that change. Cleanup will come.
>> @@ -3332,7 +3376,7 @@
>> Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
>>
>> QualType ArgType = OperType->getArgType(0);
>> - if (!ArgType->isReferenceType()) {
>> + if (!ArgType->isLValueReferenceType()) {
>> Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref);
>> HadError = true;
>> } else {
>> @@ -3384,6 +3428,155 @@
>> }
>> }
>>
>> +void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) {
>> + assert(CD->isExplicitlyDefaulted() && CD->isMoveConstructor());
>> +
>> + // Whether this was the first-declared instance of the constructor.
>> + bool First = CD == CD->getCanonicalDecl();
>> +
>> + bool HadError = false;
>> + if (CD->getNumParams() != 1) {
>> + Diag(CD->getLocation(), diag::err_defaulted_move_ctor_params)
>> + << CD->getSourceRange();
>> + HadError = true;
>> + }
>> +
>> + ImplicitExceptionSpecification Spec(
>> + ComputeDefaultedMoveCtorExceptionSpec(CD->getParent()));
>> +
>> + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
>> + const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
>> + *ExceptionType = Context.getFunctionType(
>> + Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
>> +
>> + // Check for parameter type matching.
>> + // This is a move ctor so we know it's a cv-qualified rvalue reference to T.
>> + QualType ArgType = CtorType->getArgType(0);
>> + if (ArgType->getPointeeType().isVolatileQualified()) {
>> + Diag(CD->getLocation(), diag::err_defaulted_move_ctor_volatile_param);
>> + HadError = true;
>> + }
>> + if (ArgType->getPointeeType().isConstQualified()) {
>> + Diag(CD->getLocation(), diag::err_defaulted_move_ctor_const_param);
>> + HadError = true;
>> + }
>
> Shouldn't we just check for any qualifiers here? We wouldn't want it to be restrict-qualifier, or address-space-256-qualified, or any other ridiculous non-C++ qualifier.
Yes. And I also should fold the various diagnostics into one.
Thanks for the review.
Sebastian
More information about the cfe-commits
mailing list