[PATCH] Prevent gnu-expression-statements from clobbering potential lambda captures

Faisal Vali faisalv at yahoo.com
Wed Nov 13 07:41:59 PST 2013


Hi rsmith, doug.gregor,

As pointed out by Richard:
  void test() {
    const int x = 10;
    [=](auto a) {
      return [=](auto b) {
        return +x + ({0;b;}); <-- this would prevent x from being captured - though we need it to be per the standard
      };
    }; 
 }

This is fixed by saving adn restoring the state associated with potential-captures (similar to how MaybeODRUsedExprs are handled) when a new expression eval context is pushed on the stack.

Interestingly - the instantiation dependence of the full gnu-expression statement (or the individual expression-statements) does not percolate through to the containing full expression.  
The temporary fix i introduced only works if the final expression-statement is type dependent - but won't work for {(0; b; 0});
Any thoughts on how to fix this too?

http://llvm-reviews.chandlerc.com/D2170

Files:
  include/clang/Sema/ScopeInfo.h
  include/clang/Sema/Sema.h
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaExprCXX.cpp

Index: include/clang/Sema/ScopeInfo.h
===================================================================
--- include/clang/Sema/ScopeInfo.h
+++ include/clang/Sema/ScopeInfo.h
@@ -751,8 +751,19 @@
   }
   void clearPotentialCaptures() {
     PotentiallyCapturingExprs.clear();
+    NonODRUsedCapturingExprs.clear();
     PotentialThisCaptureLocation = SourceLocation();
   }
+  void swapPotentialCaptures(llvm::SmallVectorImpl<Expr *> &PotCapExprs,
+      llvm::SmallSet<Expr *, 8> &NonODRUsedCapExprs, 
+      SourceLocation &PotThisCapLoc) {
+    PotentiallyCapturingExprs.swap(PotCapExprs);
+    NonODRUsedCapturingExprs.swap(NonODRUsedCapExprs);
+    SourceLocation Tmp = PotThisCapLoc;
+    PotThisCapLoc = PotentialThisCaptureLocation;
+    PotentialThisCaptureLocation = Tmp;
+  }
+       
   unsigned getNumPotentialVariableCaptures() const { 
     return PotentiallyCapturingExprs.size(); 
   }
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -662,7 +662,11 @@
     unsigned NumCleanupObjects;
 
     llvm::SmallPtrSet<Expr*, 2> SavedMaybeODRUseExprs;
+    llvm::SmallSet<Expr*, 8> SavedLambdaNonODRUsedCapturingExprs;
+    llvm::SmallVector<Expr*, 4> SavedLambdaPotentiallyCapturingExprs;
+    SourceLocation SavedLambdaPotentialThisCaptureLocation;
 
+
     /// \brief The lambdas that are present within this context, if it
     /// is indeed an unevaluated context.
     SmallVector<LambdaExpr *, 2> Lambdas;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -11015,9 +11015,15 @@
                                                ExprNeedsCleanups,
                                                LambdaContextDecl,
                                                IsDecltype));
+  ExpressionEvaluationContextRecord &ER = ExprEvalContexts.back();
   ExprNeedsCleanups = false;
   if (!MaybeODRUseExprs.empty())
-    std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs);
+    std::swap(MaybeODRUseExprs, ER.SavedMaybeODRUseExprs);
+  if (sema::LambdaScopeInfo *LSI = getCurLambda()) {
+    LSI->swapPotentialCaptures(ER.SavedLambdaPotentiallyCapturingExprs, 
+        ER.SavedLambdaNonODRUsedCapturingExprs, 
+        ER.SavedLambdaPotentialThisCaptureLocation);
+  }
 }
 
 void
@@ -11062,7 +11068,7 @@
       }
     }
   }
-
+  sema::LambdaScopeInfo *const LSI = getCurLambda();
   // When are coming out of an unevaluated context, clear out any
   // temporaries that we may have created as part of the evaluation of
   // the expression in that context: they aren't relevant because they
@@ -11073,11 +11079,27 @@
     ExprNeedsCleanups = Rec.ParentNeedsCleanups;
     CleanupVarDeclMarking();
     std::swap(MaybeODRUseExprs, Rec.SavedMaybeODRUseExprs);
+    if (LSI)
+      LSI->swapPotentialCaptures(Rec.SavedLambdaPotentiallyCapturingExprs, 
+          Rec.SavedLambdaNonODRUsedCapturingExprs, 
+          Rec.SavedLambdaPotentialThisCaptureLocation);
   // Otherwise, merge the contexts together.
   } else {
     ExprNeedsCleanups |= Rec.ParentNeedsCleanups;
     MaybeODRUseExprs.insert(Rec.SavedMaybeODRUseExprs.begin(),
                             Rec.SavedMaybeODRUseExprs.end());
+    if (LSI) {
+      LSI->PotentiallyCapturingExprs.append(
+          Rec.SavedLambdaPotentiallyCapturingExprs.begin(), 
+          Rec.SavedLambdaPotentiallyCapturingExprs.end());
+      LSI->NonODRUsedCapturingExprs.insert(
+          Rec.SavedLambdaNonODRUsedCapturingExprs.begin(),
+          Rec.SavedLambdaNonODRUsedCapturingExprs.end());
+      if (!LSI->PotentialThisCaptureLocation.isValid())  
+        LSI->PotentialThisCaptureLocation = 
+            Rec.SavedLambdaPotentialThisCaptureLocation;
+
+    }
   }
 
   // Pop the current expression evaluation context off the stack.
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5863,8 +5863,19 @@
     
   assert(!S.isUnevaluatedContext());  
   assert(S.CurContext->isDependentContext()); 
+  // We need the type-dependence check too because the instantiation dependence
+  // doesn't percolate through gnu-statement expressions.
+  // For e.g.,:
+  //  const int x = 10;
+  //  [=](auto a) {
+  //    return [=](auto b) {
+  //      return +x + ({0;b;}); <-- this is not instantiation dependent?!
+  //    };
+  //  }; 
+  // FIXME: If an expression is type-dependent, it should end up being 
+  // instantiation dependent too.
   const bool IsFullExprInstantiationDependent = 
-      FE->isInstantiationDependent();
+      FE->isInstantiationDependent() || FE->isTypeDependent();
   // All the potentially captureable variables in the current nested 
   // lambda (within a generic outer lambda), must be captured by an
   // outer lambda that is enclosed within a non-dependent context.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D2170.1.patch
Type: text/x-patch
Size: 5014 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131113/4f3fc1b5/attachment.bin>


More information about the cfe-commits mailing list