[cfe-commits] r130642 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/AST/ExprCXX.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Initialization.h include/clang/Sema/Sema.h lib/CodeGen/CGClass.cpp lib/CodeGen/CGExprCXX.cpp lib/CodeGen/CodeGenFunction.h lib/Lex/PPMacroExpansion.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaInit.cpp test/CodeGenCXX/cxx0x-delegating-ctors.cpp test/SemaCXX/cxx0x-delegating-ctors.cpp www/cxx_status.html

Sean Hunt scshunt at csclub.uwaterloo.ca
Sun May 1 09:00:21 PDT 2011


On 11-05-01 04:14 AM, John McCall wrote:
> On May 1, 2011, at 12:04 AM, Sean Hunt wrote:
>> Modified: cfe/trunk/include/clang/AST/DeclCXX.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=130642&r1=130641&r2=130642&view=diff
>> <http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=130642&r1=130641&r2=130642&view=diff>
>> ==============================================================================
>> --- cfe/trunk/include/clang/AST/DeclCXX.h (original)
>> +++ cfe/trunk/include/clang/AST/DeclCXX.h Sun May 1 02:04:31 2011
>> @@ -1608,6 +1608,23 @@
>> void setCtorInitializers(CXXCtorInitializer ** initializers) {
>> CtorInitializers = initializers;
>> }
>> +
>> + /// isDelegatingConstructor - Whether this constructor is a
>> + /// delegating constructor
>> + bool isDelegatingConstructor() const {
>> + return (getNumCtorInitializers() == 1) &&
>> + CtorInitializers[0]->isDelegatingInitializer();
>> + }
>> +
>> + /// getTargetConstructor - When this constructor delegates to
>> + /// another, retrieve the target
>> + CXXConstructorDecl *getTargetConstructor() const {
>> + if (isDelegatingConstructor())
>> + return CtorInitializers[0]->getTargetConstructor();
>> + else
>> + return 0;
>> + }
>> +
>
> My preference would be for this method to assert(isDelegatingConstructor()).
> Also, I think the name ought to have 'delegate' in there somewhere, maybe
> 'getDelegateTargetConstructor()'.

Okay. I wasn't really sure on the conventions, and this variant made its 
uses quicker to write. I don't have strong preferences.

>> Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=130642&r1=130641&r2=130642&view=diff
>> <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=130642&r1=130641&r2=130642&view=diff>
>> ==============================================================================
>> --- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
>> +++ cfe/trunk/lib/CodeGen/CGClass.cpp Sun May 1 02:04:31 2011
>> @@ -658,6 +658,10 @@
>> if (Ctor->getType()->getAs<FunctionProtoType>()->isVariadic())
>> return false;
>>
>> + // FIXME: Decide if we can do a delegation of a delegating constructor.
>> + if (Ctor->isDelegatingConstructor())
>> + return false;
>> +
>
> Complete-to-base delegation is still fine for delegating constructors if
> there are no virtual bases, because by definition the complete and base
> variants of the target constructor are equivalent.

I think so, but I'd rather not accidentally break something and have to 
fix it later. Moreover, applying this optimization won't lead to a lot 
of direct speedup as we'll still have three constructors total being 
called. Writing a version of the optimization that causes the delegating 
complete constructor to do the VTT setup (which it normally doesn't as 
the target constructor does that) and then call into the base target 
constructor is probably ideal.

>> @@ -721,8 +728,10 @@
>>
>> if (Member->isBaseInitializer())
>> EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
>> - else
>> + else if (Member->isAnyMemberInitializer())
>> MemberInitializers.push_back(Member);
>> + else
>> + llvm_unreachable("Delegating initializer on non-delegating
>> constructor");
>> }
>
> Better to just assert(Member->isAnyMemberInitializer());

Good catch.

>> +void
>> +CodeGenFunction::EmitDelegatingCXXConstructorCall(const
>> CXXConstructorDecl *Ctor,
>> + const FunctionArgList &Args) {
>> + assert(Ctor->isDelegatingConstructor());
>> +
>> + llvm::Value *ThisPtr = LoadCXXThis();
>> +
>> + AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, false,
>> /*Lifetime*/ true);
>> +
>> + EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot);
>> +}
>
> This is clever. After the delegate call succeeds, though, you do
> need to push a cleanup to call the dtor if an exception is thrown
> in the body of the delegating constructor.

Thanks! I thought I had everything but you're right about this.

>> Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=130642&r1=130641&r2=130642&view=diff
>> <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=130642&r1=130641&r2=130642&view=diff>
>> ==============================================================================
>> --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
>> +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Sun May 1 02:04:31 2011
>> @@ -404,9 +404,16 @@
>> E->arg_begin(), E->arg_end());
>> }
>> else {
>> - CXXCtorType Type =
>> - (E->getConstructionKind() == CXXConstructExpr::CK_Complete)
>> - ? Ctor_Complete : Ctor_Base;
>> + CXXCtorType Type;
>> + CXXConstructExpr::ConstructionKind K = E->getConstructionKind();
>> + if (K == CXXConstructExpr::CK_Delegating) {
>> + // We should be emitting a constructor; GlobalDecl will assert this
>> + Type = CurGD.getCtorType();
>> + } else {
>> + Type = (E->getConstructionKind() == CXXConstructExpr::CK_Complete)
>> + ? Ctor_Complete : Ctor_Base;
>> + }
>
> Since this is already inside an if/else, go ahead and break up this
> ternary operator, or even consider using a switch over the construction
> kind.

Okay.

>> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=130642&r1=130641&r2=130642&view=diff
>> <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=130642&r1=130641&r2=130642&view=diff>
>> ==============================================================================
>> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun May 1 02:04:31 2011
>> @@ -2068,6 +2068,30 @@
>>
>> return false;
>> }
>> +
>> +bool
>> +Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
>> + CXXCtorInitializer *Initializer) {
>> + Constructor->setNumCtorInitializers(1);
>> + CXXCtorInitializer **initializer =
>> + new (Context) CXXCtorInitializer*[1];
>> + memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*));
>> + Constructor->setCtorInitializers(initializer);
>> +
>> + // FIXME: This doesn't catch indirect loops yet
>> + CXXConstructorDecl *Target = Initializer->getTargetConstructor();
>> + while (Target) {
>> + if (Target == Constructor) {
>> + Diag(Initializer->getSourceLocation(), diag::err_delegating_ctor_loop)
>> + << Constructor;
>> + return true;
>> + }
>> + Target = Target->getTargetConstructor();
>> + }
>> +
>> + return false;
>> +}
>
> Is this FIXME still correct? It certainly looks like it detects loops of
> arbitrary length.

Yes, it is. In an indirect loop, the issue of multiple Decls for the 
same object comes into play. Pretty easy fix, but it was late and is 
just QOI.

> However, it also looks like it can infinite-loop if there's a loop not
> involving the current constructor, e.g.
> MyClass() : MyClass(0) {}
> MyClass(int x) : MyClass() { this->x = x; } // should get an error here,
> but then...
> MyClass(int x, int y) : MyClass(x) { this->y = y; } // this will
> infinite loop.
>
> John.

I'm not too concerned about this case, since when the second one errors 
and the user fixes that, then we're good. Doesn't seem very good to give 
errors multiple times.

Sean



More information about the cfe-commits mailing list