[llvm-branch-commits] [cfe-branch] r196470 - Merging r196454:

Bill Wendling isanbard at gmail.com
Fri Dec 6 01:12:03 PST 2013


Okay, fixed. Thanks for letting me know.

-bw

On Dec 6, 2013, at 1:01 AM, NAKAMURA Takumi <geek4civic at gmail.com> wrote:

> Bill, it requires merging r196459 to suppress warnings.
> 
> 2013/12/5 Bill Wendling <isanbard at gmail.com>:
>> Author: void
>> Date: Wed Dec  4 23:25:04 2013
>> New Revision: 196470
>> 
>> URL: http://llvm.org/viewvc/llvm-project?rev=196470&view=rev
>> Log:
>> Merging r196454:
>> ------------------------------------------------------------------------
>> r196454 | faisalv | 2013-12-04 17:40:41 -0800 (Wed, 04 Dec 2013) | 43 lines
>> 
>> Fix init-captures for generic lambdas.
>> 
>> For an init capture, process the initialization expression
>> right away.  For lambda init-captures such as the following:
>> const int x = 10;
>> auto L = [i = x+1](int a) {
>>   return [j = x+2,
>>          &k = x](char b) { };
>> };
>> keep in mind that each lambda init-capture has to have:
>> - its initialization expression executed in the context
>>   of the enclosing/parent decl-context.
>> - but the variable itself has to be 'injected' into the
>>   decl-context of its lambda's call-operator (which has
>>   not yet been created).
>> Each init-expression is a full-expression that has to get
>> Sema-analyzed (for capturing etc.) before its lambda's
>> call-operator's decl-context, scope & scopeinfo are pushed on their
>> respective stacks.  Thus if any variable is odr-used in the init-capture
>> it will correctly get captured in the enclosing lambda, if one exists.
>> The init-variables above are created later once the lambdascope and
>> call-operators decl-context is pushed onto its respective stack.
>> 
>> Since the lambda init-capture's initializer expression occurs in the
>> context of the enclosing function or lambda, therefore we can not wait
>> till a lambda scope has been pushed on before deciding whether the
>> variable needs to be captured.  We also need to process all
>> lvalue-to-rvalue conversions and discarded-value conversions,
>> so that we can avoid capturing certain constant variables.
>> For e.g.,
>> void test() {
>>  const int x = 10;
>>  auto L = [&z = x](char a) { <-- don't capture by the current lambda
>>    return [y = x](int i) { <-- don't capture by enclosing lambda
>>         return y;
>>    }
>>  };
>> If x was not const, the second use would require 'L' to capture, and
>> that would be an error.
>> Make sure TranformLambdaExpr is also aware of this.
>> 
>> Patch approved by Richard (Thanks!!)
>> http://llvm-reviews.chandlerc.com/D2092
>> ------------------------------------------------------------------------
>> 
>> Modified:
>>    cfe/branches/release_34/   (props changed)
>>    cfe/branches/release_34/include/clang/Sema/DeclSpec.h
>>    cfe/branches/release_34/include/clang/Sema/Initialization.h
>>    cfe/branches/release_34/include/clang/Sema/Sema.h
>>    cfe/branches/release_34/lib/Parse/ParseExprCXX.cpp
>>    cfe/branches/release_34/lib/Sema/SemaAccess.cpp
>>    cfe/branches/release_34/lib/Sema/SemaExpr.cpp
>>    cfe/branches/release_34/lib/Sema/SemaExprCXX.cpp
>>    cfe/branches/release_34/lib/Sema/SemaInit.cpp
>>    cfe/branches/release_34/lib/Sema/SemaLambda.cpp
>>    cfe/branches/release_34/lib/Sema/SemaTemplateInstantiate.cpp
>>    cfe/branches/release_34/lib/Sema/TreeTransform.h
>>    cfe/branches/release_34/test/SemaCXX/cxx1y-init-captures.cpp
>> 
>> Propchange: cfe/branches/release_34/
>> ------------------------------------------------------------------------------
>> --- svn:mergeinfo (original)
>> +++ svn:mergeinfo Wed Dec  4 23:25:04 2013
>> @@ -1,4 +1,4 @@
>> /cfe/branches/type-system-rewrite:134693-134817
>> -/cfe/trunk:195126,195128,195135-195136,195146,195149,195154,195158,195163,195168,195174,195249,195268,195283,195303,195326,195329,195367,195384,195409,195420,195422,195501,195547,195556,195558,195587,195620,195635,195669,195687,195693,195710,195713,195716,195756,195760,195768,195777,195789,195792,195804,195827,195843-195844,195877,195887-195888,195897,195903,195905-195906,195932,195936-195943,195970,195983,196045,196048,196050,196058,196114-196115,196153,196206,196215,196370,196423
>> +/cfe/trunk:195126,195128,195135-195136,195146,195149,195154,195158,195163,195168,195174,195249,195268,195283,195303,195326,195329,195367,195384,195409,195420,195422,195501,195547,195556,195558,195587,195620,195635,195669,195687,195693,195710,195713,195716,195756,195760,195768,195777,195789,195792,195804,195827,195843-195844,195877,195887-195888,195897,195903,195905-195906,195932,195936-195943,195970,195983,196045,196048,196050,196058,196114-196115,196153,196206,196215,196370,196423,196454
>> /cfe/trunk/test:170344
>> /cfe/trunk/test/SemaTemplate:126920
>> 
>> Modified: cfe/branches/release_34/include/clang/Sema/DeclSpec.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/include/clang/Sema/DeclSpec.h?rev=196470&r1=196469&r2=196470&view=diff
>> ==============================================================================
>> --- cfe/branches/release_34/include/clang/Sema/DeclSpec.h (original)
>> +++ cfe/branches/release_34/include/clang/Sema/DeclSpec.h Wed Dec  4 23:25:04 2013
>> @@ -2166,12 +2166,13 @@ struct LambdaCapture {
>>   IdentifierInfo *Id;
>>   SourceLocation EllipsisLoc;
>>   ExprResult Init;
>> -
>> +  ParsedType InitCaptureType;
>>   LambdaCapture(LambdaCaptureKind Kind, SourceLocation Loc,
>> -                IdentifierInfo* Id = 0,
>> -                SourceLocation EllipsisLoc = SourceLocation(),
>> -                ExprResult Init = ExprResult())
>> -    : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc), Init(Init)
>> +                IdentifierInfo* Id,
>> +                SourceLocation EllipsisLoc,
>> +                ExprResult Init, ParsedType InitCaptureType)
>> +    : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc), Init(Init),
>> +        InitCaptureType(InitCaptureType)
>>   {}
>> };
>> 
>> @@ -2188,10 +2189,12 @@ struct LambdaIntroducer {
>>   /// \brief Append a capture in a lambda introducer.
>>   void addCapture(LambdaCaptureKind Kind,
>>                   SourceLocation Loc,
>> -                  IdentifierInfo* Id = 0,
>> -                  SourceLocation EllipsisLoc = SourceLocation(),
>> -                  ExprResult Init = ExprResult()) {
>> -    Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc, Init));
>> +                  IdentifierInfo* Id,
>> +                  SourceLocation EllipsisLoc,
>> +                  ExprResult Init,
>> +                  ParsedType InitCaptureType) {
>> +    Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc, Init,
>> +        InitCaptureType));
>>   }
>> };
>> 
>> 
>> Modified: cfe/branches/release_34/include/clang/Sema/Initialization.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/include/clang/Sema/Initialization.h?rev=196470&r1=196469&r2=196470&view=diff
>> ==============================================================================
>> --- cfe/branches/release_34/include/clang/Sema/Initialization.h (original)
>> +++ cfe/branches/release_34/include/clang/Sema/Initialization.h Wed Dec  4 23:25:04 2013
>> @@ -116,8 +116,8 @@ private:
>>   };
>> 
>>   struct C {
>> -    /// \brief The variable being captured by an EK_LambdaCapture.
>> -    VarDecl *Var;
>> +    /// \brief The name of the variable being captured by an EK_LambdaCapture.
>> +    IdentifierInfo *VarID;
>> 
>>     /// \brief The source location at which the capture occurs.
>>     unsigned Location;
>> @@ -183,10 +183,10 @@ private:
>>                     const InitializedEntity &Parent);
>> 
>>   /// \brief Create the initialization entity for a lambda capture.
>> -  InitializedEntity(VarDecl *Var, FieldDecl *Field, SourceLocation Loc)
>> -    : Kind(EK_LambdaCapture), Parent(0), Type(Field->getType())
>> +  InitializedEntity(IdentifierInfo *VarID, QualType FieldType, SourceLocation Loc)
>> +    : Kind(EK_LambdaCapture), Parent(0), Type(FieldType)
>>   {
>> -    Capture.Var = Var;
>> +    Capture.VarID = VarID;
>>     Capture.Location = Loc.getRawEncoding();
>>   }
>> 
>> @@ -309,10 +309,10 @@ public:
>>   }
>> 
>>   /// \brief Create the initialization entity for a lambda capture.
>> -  static InitializedEntity InitializeLambdaCapture(VarDecl *Var,
>> -                                                   FieldDecl *Field,
>> +  static InitializedEntity InitializeLambdaCapture(IdentifierInfo *VarID,
>> +                                                   QualType FieldType,
>>                                                    SourceLocation Loc) {
>> -    return InitializedEntity(Var, Field, Loc);
>> +    return InitializedEntity(VarID, FieldType, Loc);
>>   }
>> 
>>   /// \brief Create the entity for a compound literal initializer.
>> @@ -402,13 +402,11 @@ public:
>>            getKind() == EK_ComplexElement);
>>     this->Index = Index;
>>   }
>> -
>> -  /// \brief Retrieve the variable for a captured variable in a lambda.
>> -  VarDecl *getCapturedVar() const {
>> +  /// \brief For a lambda capture, return the capture's name.
>> +  StringRef getCapturedVarName() const {
>>     assert(getKind() == EK_LambdaCapture && "Not a lambda capture!");
>> -    return Capture.Var;
>> +    return Capture.VarID->getName();
>>   }
>> -
>>   /// \brief Determine the location of the capture when initializing
>>   /// field from a captured variable in a lambda.
>>   SourceLocation getCaptureLoc() const {
>> 
>> Modified: cfe/branches/release_34/include/clang/Sema/Sema.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/include/clang/Sema/Sema.h?rev=196470&r1=196469&r2=196470&view=diff
>> ==============================================================================
>> --- cfe/branches/release_34/include/clang/Sema/Sema.h (original)
>> +++ cfe/branches/release_34/include/clang/Sema/Sema.h Wed Dec  4 23:25:04 2013
>> @@ -281,6 +281,12 @@ public:
>>   /// element type here is ExprWithCleanups::Object.
>>   SmallVector<BlockDecl*, 8> ExprCleanupObjects;
>> 
>> +  /// \brief Store a list of either DeclRefExprs or MemberExprs
>> +  ///  that contain a reference to a variable (constant) that may or may not
>> +  ///  be odr-used in this Expr, and we won't know until all lvalue-to-rvalue
>> +  ///  and discarded value conversions have been applied to all subexpressions
>> +  ///  of the enclosing full expression.  This is cleared at the end of each
>> +  ///  full expression.
>>   llvm::SmallPtrSet<Expr*, 2> MaybeODRUseExprs;
>> 
>>   /// \brief Stack containing information about each of the nested
>> @@ -4311,7 +4317,8 @@ public:
>>   }
>>   ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC,
>>                                  bool DiscardedValue = false,
>> -                                 bool IsConstexpr = false);
>> +                                 bool IsConstexpr = false,
>> +                                 bool IsLambdaInitCaptureInitializer = false);
>>   StmtResult ActOnFinishFullStmt(Stmt *Stmt);
>> 
>>   // Marks SS invalid if it represents an incomplete type.
>> @@ -4506,10 +4513,18 @@ public:
>>                         bool ExplicitResultType,
>>                         bool Mutable);
>> 
>> -  /// \brief Check an init-capture and build the implied variable declaration
>> -  /// with the specified name and initializer.
>> -  VarDecl *checkInitCapture(SourceLocation Loc, bool ByRef,
>> -                            IdentifierInfo *Id, Expr *Init);
>> +  /// \brief Perform initialization analysis of the init-capture and perform
>> +  /// any implicit conversions such as an lvalue-to-rvalue conversion if
>> +  /// not being used to initialize a reference.
>> +  QualType performLambdaInitCaptureInitialization(SourceLocation Loc,
>> +      bool ByRef, IdentifierInfo *Id, Expr *&Init);
>> +  /// \brief Create a dummy variable within the declcontext of the lambda's
>> +  ///  call operator, for name lookup purposes for a lambda init capture.
>> +  ///
>> +  ///  CodeGen handles emission of lambda captures, ignoring these dummy
>> +  ///  variables appropriately.
>> +  VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc,
>> +    QualType InitCaptureType, IdentifierInfo *Id, Expr *Init);
>> 
>>   /// \brief Build the implicit field for an init-capture.
>>   FieldDecl *buildInitCaptureField(sema::LambdaScopeInfo *LSI, VarDecl *Var);
>> 
>> Modified: cfe/branches/release_34/lib/Parse/ParseExprCXX.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Parse/ParseExprCXX.cpp?rev=196470&r1=196469&r2=196470&view=diff
>> ==============================================================================
>> --- cfe/branches/release_34/lib/Parse/ParseExprCXX.cpp (original)
>> +++ cfe/branches/release_34/lib/Parse/ParseExprCXX.cpp Wed Dec  4 23:25:04 2013
>> @@ -633,8 +633,7 @@ ExprResult Parser::ParseCXXIdExpression(
>> ExprResult Parser::ParseLambdaExpression() {
>>   // Parse lambda-introducer.
>>   LambdaIntroducer Intro;
>> -
>> -  Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
>> +  Optional<unsigned> DiagID = ParseLambdaIntroducer(Intro);
>>   if (DiagID) {
>>     Diag(Tok, DiagID.getValue());
>>     SkipUntil(tok::r_square, StopAtSemi);
>> @@ -674,7 +673,7 @@ ExprResult Parser::TryParseLambdaExpress
>>   if (Next.is(tok::identifier) && After.is(tok::identifier)) {
>>     return ExprEmpty();
>>   }
>> -
>> +
>>   // Here, we're stuck: lambda introducers and Objective-C message sends are
>>   // unambiguous, but it requires arbitrary lookhead.  [a,b,c,d,e,f,g] is a
>>   // lambda, and [a,b,c,d,e,f,g h] is a Objective-C message send.  Instead of
>> @@ -684,6 +683,7 @@ ExprResult Parser::TryParseLambdaExpress
>>   LambdaIntroducer Intro;
>>   if (TryParseLambdaIntroducer(Intro))
>>     return ExprEmpty();
>> +
>>   return ParseLambdaExpressionAfterIntroducer(Intro);
>> }
>> 
>> @@ -809,6 +809,11 @@ Optional<unsigned> Parser::ParseLambdaIn
>>                                             Exprs);
>>         }
>>       } else if (Tok.is(tok::l_brace) || Tok.is(tok::equal)) {
>> +        // Each lambda init-capture forms its own full expression, which clears
>> +        // Actions.MaybeODRUseExprs. So create an expression evaluation context
>> +        // to save the necessary state, and restore it later.
>> +        EnterExpressionEvaluationContext EC(Actions,
>> +                                            Sema::PotentiallyEvaluated);
>>         if (Tok.is(tok::equal))
>>           ConsumeToken();
>> 
>> @@ -862,13 +867,61 @@ Optional<unsigned> Parser::ParseLambdaIn
>>       } else if (Tok.is(tok::ellipsis))
>>         EllipsisLoc = ConsumeToken();
>>     }
>> -
>> -    Intro.addCapture(Kind, Loc, Id, EllipsisLoc, Init);
>> +    // If this is an init capture, process the initialization expression
>> +    // right away.  For lambda init-captures such as the following:
>> +    // const int x = 10;
>> +    //  auto L = [i = x+1](int a) {
>> +    //    return [j = x+2,
>> +    //           &k = x](char b) { };
>> +    //  };
>> +    // keep in mind that each lambda init-capture has to have:
>> +    //  - its initialization expression executed in the context
>> +    //    of the enclosing/parent decl-context.
>> +    //  - but the variable itself has to be 'injected' into the
>> +    //    decl-context of its lambda's call-operator (which has
>> +    //    not yet been created).
>> +    // Each init-expression is a full-expression that has to get
>> +    // Sema-analyzed (for capturing etc.) before its lambda's
>> +    // call-operator's decl-context, scope & scopeinfo are pushed on their
>> +    // respective stacks.  Thus if any variable is odr-used in the init-capture
>> +    // it will correctly get captured in the enclosing lambda, if one exists.
>> +    // The init-variables above are created later once the lambdascope and
>> +    // call-operators decl-context is pushed onto its respective stack.
>> +
>> +    // Since the lambda init-capture's initializer expression occurs in the
>> +    // context of the enclosing function or lambda, therefore we can not wait
>> +    // till a lambda scope has been pushed on before deciding whether the
>> +    // variable needs to be captured.  We also need to process all
>> +    // lvalue-to-rvalue conversions and discarded-value conversions,
>> +    // so that we can avoid capturing certain constant variables.
>> +    // For e.g.,
>> +    //  void test() {
>> +    //   const int x = 10;
>> +    //   auto L = [&z = x](char a) { <-- don't capture by the current lambda
>> +    //     return [y = x](int i) { <-- don't capture by enclosing lambda
>> +    //          return y;
>> +    //     }
>> +    //   };
>> +    // If x was not const, the second use would require 'L' to capture, and
>> +    // that would be an error.
>> +
>> +    ParsedType InitCaptureParsedType;
>> +    if (Init.isUsable()) {
>> +      // Get the pointer and store it in an lvalue, so we can use it as an
>> +      // out argument.
>> +      Expr *InitExpr = Init.get();
>> +      // This performs any lvalue-to-rvalue conversions if necessary, which
>> +      // can affect what gets captured in the containing decl-context.
>> +      QualType InitCaptureType = Actions.performLambdaInitCaptureInitialization(
>> +        Loc, Kind == LCK_ByRef, Id, InitExpr);
>> +      Init = InitExpr;
>> +      InitCaptureParsedType.set(InitCaptureType);
>> +    }
>> +    Intro.addCapture(Kind, Loc, Id, EllipsisLoc, Init, InitCaptureParsedType);
>>   }
>> 
>>   T.consumeClose();
>>   Intro.Range.setEnd(T.getCloseLocation());
>> -
>>   return DiagResult();
>> }
>> 
>> 
>> Modified: cfe/branches/release_34/lib/Sema/SemaAccess.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Sema/SemaAccess.cpp?rev=196470&r1=196469&r2=196470&view=diff
>> ==============================================================================
>> --- cfe/branches/release_34/lib/Sema/SemaAccess.cpp (original)
>> +++ cfe/branches/release_34/lib/Sema/SemaAccess.cpp Wed Dec  4 23:25:04 2013
>> @@ -1650,9 +1650,9 @@ Sema::AccessResult Sema::CheckConstructo
>>   }
>> 
>>   case InitializedEntity::EK_LambdaCapture: {
>> -    const VarDecl *Var = Entity.getCapturedVar();
>> +    StringRef VarName = Entity.getCapturedVarName();
>>     PD = PDiag(diag::err_access_lambda_capture);
>> -    PD << Var->getName() << Entity.getType() << getSpecialMember(Constructor);
>> +    PD << VarName << Entity.getType() << getSpecialMember(Constructor);
>>     break;
>>   }
>> 
>> 
>> Modified: cfe/branches/release_34/lib/Sema/SemaExpr.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Sema/SemaExpr.cpp?rev=196470&r1=196469&r2=196470&view=diff
>> ==============================================================================
>> --- cfe/branches/release_34/lib/Sema/SemaExpr.cpp (original)
>> +++ cfe/branches/release_34/lib/Sema/SemaExpr.cpp Wed Dec  4 23:25:04 2013
>> @@ -11688,7 +11688,8 @@ static ExprResult addAsFieldToClosureTyp
>>   SmallVector<InitializedEntity, 4> Entities;
>>   Entities.reserve(1 + IndexVariables.size());
>>   Entities.push_back(
>> -    InitializedEntity::InitializeLambdaCapture(Var, Field, Loc));
>> +    InitializedEntity::InitializeLambdaCapture(Var->getIdentifier(),
>> +        Field->getType(), Loc));
>>   for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
>>     Entities.push_back(InitializedEntity::InitializeElement(S.Context,
>>                                                             0,
>> 
>> Modified: cfe/branches/release_34/lib/Sema/SemaExprCXX.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Sema/SemaExprCXX.cpp?rev=196470&r1=196469&r2=196470&view=diff
>> ==============================================================================
>> --- cfe/branches/release_34/lib/Sema/SemaExprCXX.cpp (original)
>> +++ cfe/branches/release_34/lib/Sema/SemaExprCXX.cpp Wed Dec  4 23:25:04 2013
>> @@ -5929,13 +5929,30 @@ static void CheckLambdaCaptures(Expr *co
>> 
>> ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
>>                                      bool DiscardedValue,
>> -                                     bool IsConstexpr) {
>> +                                     bool IsConstexpr,
>> +                                     bool IsLambdaInitCaptureInitializer) {
>>   ExprResult FullExpr = Owned(FE);
>> 
>>   if (!FullExpr.get())
>>     return ExprError();
>> -
>> -  if (DiagnoseUnexpandedParameterPack(FullExpr.get()))
>> +
>> +  // If we are an init-expression in a lambdas init-capture, we should not
>> +  // diagnose an unexpanded pack now (will be diagnosed once lambda-expr
>> +  // containing full-expression is done).
>> +  // template<class ... Ts> void test(Ts ... t) {
>> +  //   test([&a(t)]() { <-- (t) is an init-expr that shouldn't be diagnosed now.
>> +  //     return a;
>> +  //   }() ...);
>> +  // }
>> +  // FIXME: This is a hack. It would be better if we pushed the lambda scope
>> +  // when we parse the lambda introducer, and teach capturing (but not
>> +  // unexpanded pack detection) to walk over LambdaScopeInfos which don't have a
>> +  // corresponding class yet (that is, have LambdaScopeInfo either represent a
>> +  // lambda where we've entered the introducer but not the body, or represent a
>> +  // lambda where we've entered the body, depending on where the
>> +  // parser/instantiation has got to).
>> +  if (!IsLambdaInitCaptureInitializer &&
>> +      DiagnoseUnexpandedParameterPack(FullExpr.get()))
>>     return ExprError();
>> 
>>   // Top-level expressions default to 'id' when we're in a debugger.
>> 
>> Modified: cfe/branches/release_34/lib/Sema/SemaInit.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Sema/SemaInit.cpp?rev=196470&r1=196469&r2=196470&view=diff
>> ==============================================================================
>> --- cfe/branches/release_34/lib/Sema/SemaInit.cpp (original)
>> +++ cfe/branches/release_34/lib/Sema/SemaInit.cpp Wed Dec  4 23:25:04 2013
>> @@ -2506,7 +2506,7 @@ DeclarationName InitializedEntity::getNa
>>     return VariableOrMember->getDeclName();
>> 
>>   case EK_LambdaCapture:
>> -    return Capture.Var->getDeclName();
>> +    return DeclarationName(Capture.VarID);
>> 
>>   case EK_Result:
>>   case EK_Exception:
>> @@ -2608,7 +2608,7 @@ unsigned InitializedEntity::dumpImpl(raw
>>   case EK_BlockElement: OS << "Block"; break;
>>   case EK_LambdaCapture:
>>     OS << "LambdaCapture ";
>> -    getCapturedVar()->printName(OS);
>> +    OS << DeclarationName(Capture.VarID);
>>     break;
>>   }
>> 
>> 
>> Modified: cfe/branches/release_34/lib/Sema/SemaLambda.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Sema/SemaLambda.cpp?rev=196470&r1=196469&r2=196470&view=diff
>> ==============================================================================
>> --- cfe/branches/release_34/lib/Sema/SemaLambda.cpp (original)
>> +++ cfe/branches/release_34/lib/Sema/SemaLambda.cpp Wed Dec  4 23:25:04 2013
>> @@ -609,12 +609,20 @@ void Sema::deduceClosureReturnType(Captu
>>   }
>> }
>> 
>> -VarDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef,
>> -                                IdentifierInfo *Id, Expr *Init) {
>> -  // C++1y [expr.prim.lambda]p11:
>> -  //   An init-capture behaves as if it declares and explicitly captures
>> -  //   a variable of the form
>> -  //     "auto init-capture;"
>> +QualType Sema::performLambdaInitCaptureInitialization(SourceLocation Loc,
>> +                                                      bool ByRef,
>> +                                                      IdentifierInfo *Id,
>> +                                                      Expr *&Init) {
>> +
>> +  // We do not need to distinguish between direct-list-initialization
>> +  // and copy-list-initialization here, because we will always deduce
>> +  // std::initializer_list<T>, and direct- and copy-list-initialization
>> +  // always behave the same for such a type.
>> +  // FIXME: We should model whether an '=' was present.
>> +  const bool IsDirectInit = isa<ParenListExpr>(Init) || isa<InitListExpr>(Init);
>> +
>> +  // Create an 'auto' or 'auto&' TypeSourceInfo that we can use to
>> +  // deduce against.
>>   QualType DeductType = Context.getAutoDeductType();
>>   TypeLocBuilder TLB;
>>   TLB.pushTypeSpec(DeductType).setNameLoc(Loc);
>> @@ -625,24 +633,100 @@ VarDecl *Sema::checkInitCapture(SourceLo
>>   }
>>   TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, DeductType);
>> 
>> +  // Are we a non-list direct initialization?
>> +  ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
>> +
>> +  Expr *DeduceInit = Init;
>> +  // Initializer could be a C++ direct-initializer. Deduction only works if it
>> +  // contains exactly one expression.
>> +  if (CXXDirectInit) {
>> +    if (CXXDirectInit->getNumExprs() == 0) {
>> +      Diag(CXXDirectInit->getLocStart(), diag::err_init_capture_no_expression)
>> +          << DeclarationName(Id) << TSI->getType() << Loc;
>> +      return QualType();
>> +    } else if (CXXDirectInit->getNumExprs() > 1) {
>> +      Diag(CXXDirectInit->getExpr(1)->getLocStart(),
>> +           diag::err_init_capture_multiple_expressions)
>> +          << DeclarationName(Id) << TSI->getType() << Loc;
>> +      return QualType();
>> +    } else {
>> +      DeduceInit = CXXDirectInit->getExpr(0);
>> +    }
>> +  }
>> +
>> +  // Now deduce against the initialization expression and store the deduced
>> +  // type below.
>> +  QualType DeducedType;
>> +  if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) {
>> +    if (isa<InitListExpr>(Init))
>> +      Diag(Loc, diag::err_init_capture_deduction_failure_from_init_list)
>> +          << DeclarationName(Id)
>> +          << (DeduceInit->getType().isNull() ? TSI->getType()
>> +                                             : DeduceInit->getType())
>> +          << DeduceInit->getSourceRange();
>> +    else
>> +      Diag(Loc, diag::err_init_capture_deduction_failure)
>> +          << DeclarationName(Id) << TSI->getType()
>> +          << (DeduceInit->getType().isNull() ? TSI->getType()
>> +                                             : DeduceInit->getType())
>> +          << DeduceInit->getSourceRange();
>> +  }
>> +  if (DeducedType.isNull())
>> +    return QualType();
>> +
>> +  // Perform initialization analysis and ensure any implicit conversions
>> +  // (such as lvalue-to-rvalue) are enforced.
>> +  InitializedEntity Entity =
>> +      InitializedEntity::InitializeLambdaCapture(Id, DeducedType, Loc);
>> +  InitializationKind Kind =
>> +      IsDirectInit
>> +          ? (CXXDirectInit ? InitializationKind::CreateDirect(
>> +                                 Loc, Init->getLocStart(), Init->getLocEnd())
>> +                           : InitializationKind::CreateDirectList(Loc))
>> +          : InitializationKind::CreateCopy(Loc, Init->getLocStart());
>> +
>> +  MultiExprArg Args = Init;
>> +  if (CXXDirectInit)
>> +    Args =
>> +        MultiExprArg(CXXDirectInit->getExprs(), CXXDirectInit->getNumExprs());
>> +  QualType DclT;
>> +  InitializationSequence InitSeq(*this, Entity, Kind, Args);
>> +  ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT);
>> +
>> +  if (Result.isInvalid())
>> +    return QualType();
>> +  Init = Result.takeAs<Expr>();
>> +
>> +  // The init-capture initialization is a full-expression that must be
>> +  // processed as one before we enter the declcontext of the lambda's
>> +  // call-operator.
>> +  Result = ActOnFinishFullExpr(Init, Loc, /*DiscardedValue*/ false,
>> +                               /*IsConstexpr*/ false,
>> +                               /*IsLambdaInitCaptureInitalizer*/ true);
>> +  if (Result.isInvalid())
>> +    return QualType();
>> +
>> +  Init = Result.takeAs<Expr>();
>> +  return DeducedType;
>> +}
>> +
>> +VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
>> +    QualType InitCaptureType, IdentifierInfo *Id, Expr *Init) {
>> +
>> +  TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType,
>> +      Loc);
>>   // Create a dummy variable representing the init-capture. This is not actually
>>   // used as a variable, and only exists as a way to name and refer to the
>>   // init-capture.
>>   // FIXME: Pass in separate source locations for '&' and identifier.
>>   VarDecl *NewVD = VarDecl::Create(Context, CurContext, Loc,
>> -                                   Loc, Id, TSI->getType(), TSI, SC_Auto);
>> +                                   Loc, Id, InitCaptureType, TSI, SC_Auto);
>>   NewVD->setInitCapture(true);
>>   NewVD->setReferenced(true);
>>   NewVD->markUsed(Context);
>> -
>> -  // We do not need to distinguish between direct-list-initialization
>> -  // and copy-list-initialization here, because we will always deduce
>> -  // std::initializer_list<T>, and direct- and copy-list-initialization
>> -  // always behave the same for such a type.
>> -  // FIXME: We should model whether an '=' was present.
>> -  bool DirectInit = isa<ParenListExpr>(Init) || isa<InitListExpr>(Init);
>> -  AddInitializerToDecl(NewVD, Init, DirectInit, /*ContainsAuto*/true);
>> +  NewVD->setInit(Init);
>>   return NewVD;
>> +
>> }
>> 
>> FieldDecl *Sema::buildInitCaptureField(LambdaScopeInfo *LSI, VarDecl *Var) {
>> @@ -816,7 +900,7 @@ void Sema::ActOnStartOfLambdaDefinition(
>>     if (C->Init.isInvalid())
>>       continue;
>> 
>> -    VarDecl *Var;
>> +    VarDecl *Var = 0;
>>     if (C->Init.isUsable()) {
>>       Diag(C->Loc, getLangOpts().CPlusPlus1y
>>                        ? diag::warn_cxx11_compat_init_capture
>> @@ -824,9 +908,15 @@ void Sema::ActOnStartOfLambdaDefinition(
>> 
>>       if (C->Init.get()->containsUnexpandedParameterPack())
>>         ContainsUnexpandedParameterPack = true;
>> -
>> -      Var = checkInitCapture(C->Loc, C->Kind == LCK_ByRef,
>> -                             C->Id, C->Init.take());
>> +      // If the initializer expression is usable, but the InitCaptureType
>> +      // is not, then an error has occurred - so ignore the capture for now.
>> +      // for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
>> +      // FIXME: we should create the init capture variable and mark it invalid
>> +      // in this case.
>> +      if (C->InitCaptureType.get().isNull())
>> +        continue;
>> +      Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(),
>> +            C->Id, C->Init.take());
>>       // C++1y [expr.prim.lambda]p11:
>>       //   An init-capture behaves as if it declares and explicitly
>>       //   captures a variable [...] whose declarative region is the
>> 
>> Modified: cfe/branches/release_34/lib/Sema/SemaTemplateInstantiate.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Sema/SemaTemplateInstantiate.cpp?rev=196470&r1=196469&r2=196470&view=diff
>> ==============================================================================
>> --- cfe/branches/release_34/lib/Sema/SemaTemplateInstantiate.cpp (original)
>> +++ cfe/branches/release_34/lib/Sema/SemaTemplateInstantiate.cpp Wed Dec  4 23:25:04 2013
>> @@ -917,7 +917,8 @@ namespace {
>>     }
>> 
>>     ExprResult TransformLambdaScope(LambdaExpr *E,
>> -                                    CXXMethodDecl *NewCallOperator) {
>> +        CXXMethodDecl *NewCallOperator,
>> +        ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes) {
>>       CXXMethodDecl *const OldCallOperator = E->getCallOperator();
>>       // In the generic lambda case, we set the NewTemplate to be considered
>>       // an "instantiation" of the OldTemplate.
>> @@ -936,7 +937,8 @@ namespace {
>>         NewCallOperator->setInstantiationOfMemberFunction(OldCallOperator,
>>                                                     TSK_ImplicitInstantiation);
>> 
>> -      return inherited::TransformLambdaScope(E, NewCallOperator);
>> +      return inherited::TransformLambdaScope(E, NewCallOperator,
>> +          InitCaptureExprsAndTypes);
>>     }
>>     TemplateParameterList *TransformTemplateParameterList(
>>                               TemplateParameterList *OrigTPL)  {
>> 
>> Modified: cfe/branches/release_34/lib/Sema/TreeTransform.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Sema/TreeTransform.h?rev=196470&r1=196469&r2=196470&view=diff
>> ==============================================================================
>> --- cfe/branches/release_34/lib/Sema/TreeTransform.h (original)
>> +++ cfe/branches/release_34/lib/Sema/TreeTransform.h Wed Dec  4 23:25:04 2013
>> @@ -593,9 +593,11 @@ public:
>> 
>>   StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
>>   ExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E);
>> -
>> +
>> +  typedef std::pair<ExprResult, QualType> InitCaptureInfoTy;
>>   /// \brief Transform the captures and body of a lambda expression.
>> -  ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
>> +  ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator,
>> +       ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes);
>> 
>>   TemplateParameterList *TransformTemplateParameterList(
>>         TemplateParameterList *TPL) {
>> @@ -8275,7 +8277,40 @@ TreeTransform<Derived>::TransformCXXTemp
>> template<typename Derived>
>> ExprResult
>> TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
>> -
>> +
>> +  // Transform any init-capture expressions before entering the scope of the
>> +  // lambda body, because they are not semantically within that scope.
>> +  SmallVector<InitCaptureInfoTy, 8> InitCaptureExprsAndTypes;
>> +  InitCaptureExprsAndTypes.resize(E->explicit_capture_end() -
>> +      E->explicit_capture_begin());
>> +
>> +  for (LambdaExpr::capture_iterator C = E->capture_begin(),
>> +      CEnd = E->capture_end();
>> +      C != CEnd; ++C) {
>> +    if (!C->isInitCapture())
>> +      continue;
>> +    EnterExpressionEvaluationContext  EEEC(getSema(),
>> +        Sema::PotentiallyEvaluated);
>> +    ExprResult NewExprInitResult = getDerived().TransformInitializer(
>> +        C->getCapturedVar()->getInit(),
>> +        C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
>> +
>> +    if (NewExprInitResult.isInvalid())
>> +      return ExprError();
>> +    Expr *NewExprInit = NewExprInitResult.get();
>> +
>> +    VarDecl *OldVD = C->getCapturedVar();
>> +    QualType NewInitCaptureType =
>> +        getSema().performLambdaInitCaptureInitialization(C->getLocation(),
>> +            OldVD->getType()->isReferenceType(), OldVD->getIdentifier(),
>> +            NewExprInit);
>> +    NewExprInitResult = NewExprInit;
>> +    VarDecl *NewVD = 0;
>> +    InitCaptureExprsAndTypes[C - E->capture_begin()] =
>> +        std::make_pair(NewExprInitResult, NewInitCaptureType);
>> +
>> +  }
>> +
>>   LambdaScopeInfo *LSI = getSema().PushLambdaScope();
>>   // Transform the template parameters, and add them to the current
>>   // instantiation scope. The null case is handled correctly.
>> @@ -8370,31 +8405,17 @@ TreeTransform<Derived>::TransformLambdaE
>> 
>>   getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
>> 
>> -  return getDerived().TransformLambdaScope(E, NewCallOperator);
>> +  return getDerived().TransformLambdaScope(E, NewCallOperator,
>> +      InitCaptureExprsAndTypes);
>> }
>> 
>> template<typename Derived>
>> ExprResult
>> TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
>> -                                             CXXMethodDecl *CallOperator) {
>> +    CXXMethodDecl *CallOperator,
>> +    ArrayRef<InitCaptureInfoTy> InitCaptureExprsAndTypes) {
>>   bool Invalid = false;
>> 
>> -  // Transform any init-capture expressions before entering the scope of the
>> -  // lambda.
>> -  SmallVector<ExprResult, 8> InitCaptureExprs;
>> -  InitCaptureExprs.resize(E->explicit_capture_end() -
>> -                          E->explicit_capture_begin());
>> -  for (LambdaExpr::capture_iterator C = E->capture_begin(),
>> -                                 CEnd = E->capture_end();
>> -       C != CEnd; ++C) {
>> -    if (!C->isInitCapture())
>> -      continue;
>> -    InitCaptureExprs[C - E->capture_begin()] =
>> -        getDerived().TransformInitializer(
>> -            C->getCapturedVar()->getInit(),
>> -            C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
>> -  }
>> -
>>   // Introduce the context of the call operator.
>>   Sema::ContextRAII SavedContext(getSema(), CallOperator);
>> 
>> @@ -8427,19 +8448,24 @@ TreeTransform<Derived>::TransformLambdaS
>> 
>>     // Rebuild init-captures, including the implied field declaration.
>>     if (C->isInitCapture()) {
>> -      ExprResult Init = InitCaptureExprs[C - E->capture_begin()];
>> -      if (Init.isInvalid()) {
>> +
>> +      InitCaptureInfoTy InitExprTypePair =
>> +          InitCaptureExprsAndTypes[C - E->capture_begin()];
>> +      ExprResult Init = InitExprTypePair.first;
>> +      QualType InitQualType = InitExprTypePair.second;
>> +      if (Init.isInvalid() || InitQualType.isNull()) {
>>         Invalid = true;
>>         continue;
>>       }
>>       VarDecl *OldVD = C->getCapturedVar();
>> -      VarDecl *NewVD = getSema().checkInitCapture(
>> -          C->getLocation(), OldVD->getType()->isReferenceType(),
>> -          OldVD->getIdentifier(), Init.take());
>> +      VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl(
>> +          OldVD->getLocation(), InitExprTypePair.second,
>> +          OldVD->getIdentifier(), Init.get());
>>       if (!NewVD)
>>         Invalid = true;
>> -      else
>> +      else {
>>         getDerived().transformedLocalDecl(OldVD, NewVD);
>> +      }
>>       getSema().buildInitCaptureField(LSI, NewVD);
>>       continue;
>>     }
>> 
>> Modified: cfe/branches/release_34/test/SemaCXX/cxx1y-init-captures.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/test/SemaCXX/cxx1y-init-captures.cpp?rev=196470&r1=196469&r2=196470&view=diff
>> ==============================================================================
>> --- cfe/branches/release_34/test/SemaCXX/cxx1y-init-captures.cpp (original)
>> +++ cfe/branches/release_34/test/SemaCXX/cxx1y-init-captures.cpp Wed Dec  4 23:25:04 2013
>> @@ -1,14 +1,169 @@
>> -// RUN: %clang_cc1 -std=c++1y %s -verify
>> +// RUN: %clang_cc1 -std=c++1y %s -verify -emit-llvm-only
>> 
>> -// expected-no-diagnostics
>> namespace variadic_expansion {
>> -  void f(int &, char &);
>> -
>> -  template <typename ... T> void g(T &... t) {
>> +  int f(int &, char &) { return 0; }
>> +  template<class ... Ts> char fv(Ts ... ts) { return 0; }
>> +  // FIXME: why do we get 2 error messages
>> +  template <typename ... T> void g(T &... t) { //expected-note3{{declared here}}
>>     f([&a(t)]()->decltype(auto) {
>>       return a;
>>     }() ...);
>> +
>> +    auto L = [x = f([&a(t)]()->decltype(auto) { return a; }()...)]() { return x; };
>> +    const int y = 10;
>> +    auto M = [x = y,
>> +                &z = y](T& ... t) { };
>> +    auto N = [x = y,
>> +                &z = y, n = f(t...),
>> +                o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...), t...](T& ... s) {
>> +                  fv([&a(t)]()->decltype(auto) {
>> +                    return a;
>> +                  }() ...);
>> +                };
>> +    auto N2 = [x = y,                     //expected-note3{{begins here}}
>> +                &z = y, n = f(t...),
>> +                o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...)](T& ... s) {
>> +                  fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}}
>> +                    return a;
>> +                  }() ...);
>> +                };
>> +
>> +  }
>> +
>> +  void h(int i, char c) { g(i, c); } //expected-note{{in instantiation}}
>> +}
>> +
>> +namespace odr_use_within_init_capture {
>> +
>> +int test() {
>> +
>> +  { // no captures
>> +    const int x = 10;
>> +    auto L = [z = x + 2](int a) {
>> +      auto M = [y = x - 2](char b) {
>> +        return y;
>> +      };
>> +      return M;
>> +    };
>> +
>> +  }
>> +  { // should not capture
>> +    const int x = 10;
>> +    auto L = [&z = x](int a) {
>> +      return a;;
>> +    };
>> +
>> +  }
>> +  {
>> +    const int x = 10;
>> +    auto L = [k = x](char a) { //expected-note {{declared}}
>> +      return [](int b) { //expected-note {{begins}}
>> +        return [j = k](int c) { //expected-error {{cannot be implicitly captured}}
>> +          return c;
>> +        };
>> +      };
>> +    };
>> +  }
>> +  {
>> +    const int x = 10;
>> +    auto L = [k = x](char a) {
>> +      return [=](int b) {
>> +        return [j = k](int c) {
>> +          return c;
>> +        };
>> +      };
>> +    };
>>   }
>> +  {
>> +    const int x = 10;
>> +    auto L = [k = x](char a) {
>> +      return [k](int b) {
>> +        return [j = k](int c) {
>> +          return c;
>> +        };
>> +      };
>> +    };
>> +  }
>> +
>> +  return 0;
>> +}
>> 
>> -  void h(int i, char c) { g(i, c); }
>> +int run = test();
>> +
>> +}
>> +
>> +namespace odr_use_within_init_capture_template {
>> +
>> +template<class T = int>
>> +int test(T t = T{}) {
>> +
>> +  { // no captures
>> +    const T x = 10;
>> +    auto L = [z = x](char a) {
>> +      auto M = [y = x](T b) {
>> +        return y;
>> +      };
>> +      return M;
>> +    };
>> +
>> +  }
>> +  { // should not capture
>> +    const T x = 10;
>> +    auto L = [&z = x](T a) {
>> +      return a;;
>> +    };
>> +
>> +  }
>> +  { // will need to capture x in outer lambda
>> +    const T x = 10; //expected-note {{declared}}
>> +    auto L = [z = x](char a) { //expected-note {{begins}}
>> +      auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}}
>> +        return y;
>> +      };
>> +      return M;
>> +    };
>> +
>> +  }
>> +  { // will need to capture x in outer lambda
>> +    const T x = 10;
>> +    auto L = [=,z = x](char a) {
>> +      auto M = [&y = x](T b) {
>> +        return y;
>> +      };
>> +      return M;
>> +    };
>> +
>> +  }
>> +  { // will need to capture x in outer lambda
>> +    const T x = 10;
>> +    auto L = [x, z = x](char a) {
>> +      auto M = [&y = x](T b) {
>> +        return y;
>> +      };
>> +      return M;
>> +    };
>> +  }
>> +  { // will need to capture x in outer lambda
>> +    const int x = 10; //expected-note 2{{declared}}
>> +    auto L = [z = x](char a) { //expected-note 2{{begins}}
>> +      auto M = [&y = x](T b) { //expected-error 2{{cannot be implicitly captured}}
>> +        return y;
>> +      };
>> +      return M;
>> +    };
>> +  }
>> +  {
>> +    // no captures
>> +    const T x = 10;
>> +    auto L = [z =
>> +                  [z = x, &y = x](char a) { return z + y; }('a')](char a)
>> +      { return z; };
>> +
>> +  }
>> +
>> +  return 0;
>> }
>> +
>> +int run = test(); //expected-note {{instantiation}}
>> +
>> +}
>> \ No newline at end of file
>> 
>> 
>> _______________________________________________
>> llvm-branch-commits mailing list
>> llvm-branch-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-branch-commits





More information about the llvm-branch-commits mailing list