[cfe-commits] r150872 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaType.cpp test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp

Douglas Gregor dgregor at apple.com
Fri Feb 17 21:51:20 PST 2012


Author: dgregor
Date: Fri Feb 17 23:51:20 2012
New Revision: 150872

URL: http://llvm.org/viewvc/llvm-project?rev=150872&view=rev
Log:
Unify our computation of the type of a captured reference to a
variable; it was previously duplicated, and one of the copies failed
to account for outer non-mutable lambda captures.

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=150872&r1=150871&r2=150872&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Feb 17 23:51:20 2012
@@ -2327,6 +2327,10 @@
                           bool Diagnose, QualType &Type, 
                           unsigned &FunctionScopesIndex, bool &Nested);
 
+  /// \brief Given a variable, determine the type that a reference to that
+  /// variable will have in the given scope.
+  QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc);
+  
   /// \brief Determine the type of the field that will capture the
   /// given variable in a lambda expression.
   ///

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=150872&r1=150871&r2=150872&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Feb 17 23:51:20 2012
@@ -2094,42 +2094,6 @@
   return S.getCurBlock() != 0;
 }
 
-/// \brief Determine whether the given lambda would capture the given
-/// variable by copy.
-static bool willCaptureByCopy(LambdaScopeInfo *LSI, VarDecl *Var) {
-  if (LSI->isCaptured(Var))
-    return LSI->getCapture(Var).isCopyCapture();
-
-  return LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval;
-}
-
-static bool shouldAddConstQualToVarRef(ValueDecl *D, Sema &S) {
-  VarDecl *var = dyn_cast<VarDecl>(D);
-  if (!var)
-    return false;
-  if (var->getDeclContext() == S.CurContext)
-    return false;
-  if (!var->hasLocalStorage())
-    return false;
-
-  LambdaScopeInfo *LSI = S.getCurLambda();
-  if (!LSI)
-    return false;
-
-  // We don't actually allow capturing a __block variable in a lambda, but
-  // this way gives better diagnostics.
-  if (var->hasAttr<BlocksAttr>())
-    return false;
-
-  // FIXME: Does the addition of const really only apply in
-  // potentially-evaluated contexts?  The text in the lambda spec
-  // about decltype hints that it might apply in unevaluated contexts
-  // as well... and there's precent in our blocks implementation.
-  return !LSI->Mutable &&
-         S.ExprEvalContexts.back().Context != Sema::Unevaluated &&
-         willCaptureByCopy(LSI, var);
-}
-
 static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *VD,
                                         const DeclarationNameInfo &NameInfo) {
   VarDecl *var = cast<VarDecl>(VD);
@@ -2269,7 +2233,7 @@
       // fallthrough
 
     case Decl::ImplicitParam:
-    case Decl::ParmVar:
+    case Decl::ParmVar: {
       // These are always l-values.
       valueKind = VK_LValue;
       type = type.getNonReferenceType();
@@ -2277,11 +2241,18 @@
       if (shouldBuildBlockDeclRef(VD, *this))
         return BuildBlockDeclRefExpr(*this, VD, NameInfo);
 
-      if (shouldAddConstQualToVarRef(VD, *this))
-        type.addConst();
-
+      // FIXME: Does the addition of const really only apply in
+      // potentially-evaluated contexts? Since the variable isn't actually
+      // captured in an unevaluated context, it seems that the answer is no.
+      if (ExprEvalContexts.back().Context != Sema::Unevaluated) {
+        QualType CapturedType = getCapturedDeclRefType(cast<VarDecl>(VD), Loc);
+        if (!CapturedType.isNull())
+          type = CapturedType;
+      }
+      
       break;
-
+    }
+        
     case Decl::Function: {
       const FunctionType *fty = type->castAs<FunctionType>();
 
@@ -9850,6 +9821,34 @@
   return !Type->isVariablyModifiedType();
 }
 
+QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
+  QualType T = Var->getType().getNonReferenceType();
+  unsigned FunctionScopesIndex;
+  bool Nested;
+  // Determine whether we can capture this variable.
+  if (!canCaptureVariable(Var, Loc, /*Explicit=*/false, /*Diagnose=*/false, 
+                          T, FunctionScopesIndex, Nested))
+    return QualType();
+    
+  // Outer lambda scopes may have an effect on the type of a
+  // capture. Walk the captures outside-in to determine
+  // whether they can add 'const' to a capture by copy.
+  T = Var->getType().getNonReferenceType();
+  if (FunctionScopesIndex == FunctionScopes.size())
+    --FunctionScopesIndex;
+  for (unsigned I = FunctionScopesIndex, E = FunctionScopes.size();
+       I != E; ++I) {
+    CapturingScopeInfo *CSI = dyn_cast<LambdaScopeInfo>(FunctionScopes[I]);
+    if (!CSI)
+      break;
+    
+    if (shouldAddConstForScope(CSI, Var))
+      T.addConst();
+  }
+  
+  return T;
+}
+
 // Check if the variable needs to be captured; if so, try to perform
 // the capture.
 void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=150872&r1=150871&r2=150872&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Fri Feb 17 23:51:20 2012
@@ -4382,42 +4382,9 @@
     if (isa<ParenExpr>(E)) {
       if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
         if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
-          QualType T = Var->getType();
-          unsigned FunctionScopesIndex;
-          bool Nested;
-          // Determine whether we can capture this variable.
-          if (S.canCaptureVariable(Var, DRE->getLocation(), 
-                                   /*Explicit=*/false, /*Diagnose=*/false, 
-                                   T, FunctionScopesIndex, Nested)) {
-            // Outer lambda scopes may have an effect on the type of a
-            // capture. Walk the captures outside-in to determine
-            // whether they can add 'const' to a capture by copy.
-            if (FunctionScopesIndex == S.FunctionScopes.size())
-              --FunctionScopesIndex;
-            for (unsigned I = FunctionScopesIndex, 
-                          E = S.FunctionScopes.size();
-                 I != E; ++I) {
-              LambdaScopeInfo *LSI
-                = dyn_cast<LambdaScopeInfo>(S.FunctionScopes[I]);
-              if (!LSI)
-                continue;
-
-              bool ByRef = false;
-              if (LSI->isCaptured(Var))
-                ByRef = LSI->getCapture(Var).isReferenceCapture();
-              else
-                ByRef = (LSI->ImpCaptureStyle
-                           == CapturingScopeInfo::ImpCap_LambdaByref);
-
-              T = S.getLambdaCaptureFieldType(T, ByRef);
-              if (!ByRef && !LSI->Mutable)
-                T.addConst();
-            }
-
-            if (!T->isReferenceType())
-              T = S.Context.getLValueReferenceType(T);
-            return T;
-          }
+          QualType T = S.getCapturedDeclRefType(Var, DRE->getLocation());
+          if (!T.isNull())
+            return S.Context.getLValueReferenceType(T);
         }
       }
     }

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp?rev=150872&r1=150871&r2=150872&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp Fri Feb 17 23:51:20 2012
@@ -13,4 +13,7 @@
     [x] { // expected-error{{call to deleted constructor of 'const X'}}
     }();
   }();
+
+  int a; 
+  [=]{ [&] { int&x = a; }(); }(); // expected-error{{binding of reference to type 'int' to a value of type 'const int' drops qualifiers}}
 }

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp?rev=150872&r1=150871&r2=150872&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp Fri Feb 17 23:51:20 2012
@@ -17,12 +17,12 @@
   const int &irc = i;
 
   [=,&irc,&ir] {
+    static_assert(is_same<decltype(((r))), float const&>::value, 
+                  "should be const float&");
     static_assert(is_same<decltype(x), float>::value, "should be float");
     static_assert(is_same<decltype((x)), const float&>::value, 
                   "should be const float&");
     static_assert(is_same<decltype(r), float&>::value, "should be float&");
-    static_assert(is_same<decltype(((r))), float const&>::value, 
-                  "should be const float&");
     static_assert(is_same<decltype(ir), int&>::value, "should be int&");
     static_assert(is_same<decltype((ir)), int&>::value, "should be int&");
     static_assert(is_same<decltype(irc), const int&>::value, 





More information about the cfe-commits mailing list