[cfe-commits] r150347 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/Type.h include/clang/Sema/ScopeInfo.h include/clang/Sema/Sema.h lib/AST/ASTContext.cpp lib/AST/ASTImporter.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaType.cpp lib/Serialization/ASTReader.cpp lib/Serialization/ASTWriter.cpp test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp test/SemaCXX/lambda-expressions.cpp

Douglas Gregor dgregor at apple.com
Sun Feb 12 10:42:34 PST 2012


Author: dgregor
Date: Sun Feb 12 12:42:33 2012
New Revision: 150347

URL: http://llvm.org/viewvc/llvm-project?rev=150347&view=rev
Log:
Within the body of a lambda expression, decltype((x)) for an
id-expression 'x' will compute the type based on the assumption that
'x' will be captured, even if it isn't captured, per C++11
[expr.prim.lambda]p18. There are two related refactors that go into
implementing this:

  1) Split out the check that determines whether we should capture a
  particular variable reference, along with the computation of the
  type of the field, from the actual act of capturing the
  variable. 
  2) Always compute the result of decltype() within Sema, rather than
  AST, because the decltype() computation is now context-sensitive.



Added:
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp   (with props)
Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Sema/ScopeInfo.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
    cfe/trunk/test/SemaCXX/lambda-expressions.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=150347&r1=150346&r2=150347&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Sun Feb 12 12:42:33 2012
@@ -876,7 +876,7 @@
   QualType getTypeOfType(QualType t) const;
 
   /// getDecltypeType - C++0x decltype.
-  QualType getDecltypeType(Expr *e) const;
+  QualType getDecltypeType(Expr *e, QualType UnderlyingType) const;
 
   /// getUnaryTransformType - unary type transforms
   QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType,

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=150347&r1=150346&r2=150347&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Sun Feb 12 12:42:33 2012
@@ -3040,10 +3040,6 @@
 /// DecltypeType (C++0x)
 class DecltypeType : public Type {
   Expr *E;
-
-  // FIXME: We could get rid of UnderlyingType if we wanted to: We would have to
-  // Move getDesugaredType to ASTContext so that it can call getDecltypeForExpr
-  // from it.
   QualType UnderlyingType;
 
 protected:

Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=150347&r1=150346&r2=150347&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Sun Feb 12 12:42:33 2012
@@ -22,11 +22,13 @@
 namespace clang {
 
 class BlockDecl;
+class CXXMethodDecl;
 class IdentifierInfo;
 class LabelDecl;
 class ReturnStmt;
 class Scope;
 class SwitchStmt;
+class VarDecl;
 
 namespace sema {
 

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=150347&r1=150346&r2=150347&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sun Feb 12 12:42:33 2012
@@ -2282,6 +2282,34 @@
   void UpdateMarkingForLValueToRValue(Expr *E);
   void CleanupVarDeclMarking();
 
+  /// \brief Determine whether we can capture the given variable in
+  /// the given scope.
+  ///
+  /// \param Explicit Whether this is an explicit capture (vs. an
+  /// implicit capture).
+  ///
+  /// \param Diagnose Diagnose errors that occur when attempting to perform
+  /// the capture.
+  ///
+  /// \param Var The variable to check for capture.
+  ///
+  /// \param Type Will be set to the type used to perform the capture.
+  ///
+  /// \param FunctionScopesIndex Will be set to the index of the first 
+  /// scope in which capture will need to be performed.
+  ///
+  /// \param Nested Whether this will be a nested capture.
+  bool canCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit,
+                          bool Diagnose, QualType &Type, 
+                          unsigned &FunctionScopesIndex, bool &Nested);
+
+  /// \brief Determine the type of the field that will capture the
+  /// given variable in a lambda expression.
+  ///
+  /// \param T The type of the variable being captured.
+  /// \param ByRef Whether we are capturing by reference or by value.
+  QualType getLambdaCaptureFieldType(QualType T, bool ByRef);
+
   enum TryCaptureKind {
     TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef
   };

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=150347&r1=150346&r2=150347&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Sun Feb 12 12:42:33 2012
@@ -2913,44 +2913,13 @@
   return QualType(tot, 0);
 }
 
-/// getDecltypeForExpr - Given an expr, will return the decltype for that
-/// expression, according to the rules in C++0x [dcl.type.simple]p4
-static QualType getDecltypeForExpr(const Expr *e, const ASTContext &Context) {
-  if (e->isTypeDependent())
-    return Context.DependentTy;
-
-  // If e is an id expression or a class member access, decltype(e) is defined
-  // as the type of the entity named by e.
-  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(e)) {
-    if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl()))
-      return VD->getType();
-  }
-  if (const MemberExpr *ME = dyn_cast<MemberExpr>(e)) {
-    if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
-      return FD->getType();
-  }
-  // If e is a function call or an invocation of an overloaded operator,
-  // (parentheses around e are ignored), decltype(e) is defined as the
-  // return type of that function.
-  if (const CallExpr *CE = dyn_cast<CallExpr>(e->IgnoreParens()))
-    return CE->getCallReturnType();
-
-  QualType T = e->getType();
-
-  // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is
-  // defined as T&, otherwise decltype(e) is defined as T.
-  if (e->isLValue())
-    T = Context.getLValueReferenceType(T);
-
-  return T;
-}
 
 /// getDecltypeType -  Unlike many "get<Type>" functions, we don't unique
 /// DecltypeType AST's. The only motivation to unique these nodes would be
 /// memory savings. Since decltype(t) is fairly uncommon, space shouldn't be
 /// an issue. This doesn't effect the type checker, since it operates
 /// on canonical types (which are always unique).
-QualType ASTContext::getDecltypeType(Expr *e) const {
+QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const {
   DecltypeType *dt;
   
   // C++0x [temp.type]p2:
@@ -2976,8 +2945,8 @@
       dt = Canon;
     }
   } else {
-    QualType T = getDecltypeForExpr(e, *this);
-    dt = new (*this, TypeAlignment) DecltypeType(e, T, getCanonicalType(T));
+    dt = new (*this, TypeAlignment) DecltypeType(e, UnderlyingType, 
+                                      getCanonicalType(UnderlyingType));
   }
   Types.push_back(dt);
   return QualType(dt, 0);

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=150347&r1=150346&r2=150347&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Sun Feb 12 12:42:33 2012
@@ -1581,7 +1581,11 @@
   if (!ToExpr)
     return QualType();
   
-  return Importer.getToContext().getDecltypeType(ToExpr);
+  QualType UnderlyingType = Importer.Import(T->getUnderlyingType());
+  if (UnderlyingType.isNull())
+    return QualType();
+
+  return Importer.getToContext().getDecltypeType(ToExpr, UnderlyingType);
 }
 
 QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) {

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=150347&r1=150346&r2=150347&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sun Feb 12 12:42:33 2012
@@ -9566,12 +9566,7 @@
   return false;
 }
 
-/// \brief Capture the given variable in the given lambda expression.
-static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
-                                  VarDecl *Var, QualType Type, 
-                                  SourceLocation Loc, bool ByRef) {
-  CXXRecordDecl *Lambda = LSI->Lambda;
-  QualType FieldType;
+QualType Sema::getLambdaCaptureFieldType(QualType T, bool ByRef) {
   if (ByRef) {
     // C++11 [expr.prim.lambda]p15:
     //   An entity is captured by reference if it is implicitly or
@@ -9579,28 +9574,34 @@
     //   unspecified whether additional unnamed non-static data
     //   members are declared in the closure type for entities
     //   captured by reference.
-    FieldType = S.Context.getLValueReferenceType(Type.getNonReferenceType());
-  } else {
-    // C++11 [expr.prim.lambda]p14:
-    //   For each entity captured by copy, an unnamed non-static
-    //   data member is declared in the closure type. The
-    //   declaration order of these members is unspecified. The type
-    //   of such a data member is the type of the corresponding
-    //   captured entity if the entity is not a reference to an
-    //   object, or the referenced type otherwise. [Note: If the
-    //   captured entity is a reference to a function, the
-    //   corresponding data member is also a reference to a
-    //   function. - end note ]
-    if (const ReferenceType *RefType = Type->getAs<ReferenceType>()) {
-      if (!RefType->getPointeeType()->isFunctionType())
-        FieldType = RefType->getPointeeType();
-      else
-        FieldType = Type;
-    } else {
-      FieldType = Type;
-    }
+    return Context.getLValueReferenceType(T.getNonReferenceType());
+  }
+
+  // C++11 [expr.prim.lambda]p14:
+  //   For each entity captured by copy, an unnamed non-static
+  //   data member is declared in the closure type. The
+  //   declaration order of these members is unspecified. The type
+  //   of such a data member is the type of the corresponding
+  //   captured entity if the entity is not a reference to an
+  //   object, or the referenced type otherwise. [Note: If the
+  //   captured entity is a reference to a function, the
+  //   corresponding data member is also a reference to a
+  //   function. - end note ]
+  if (const ReferenceType *RefType = T->getAs<ReferenceType>()) {
+    if (!RefType->getPointeeType()->isFunctionType())
+      return RefType->getPointeeType();
   }
 
+  return T;
+}
+
+/// \brief Capture the given variable in the given lambda expression.
+static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
+                                  VarDecl *Var, QualType Type, 
+                                  SourceLocation Loc, bool ByRef) {
+  CXXRecordDecl *Lambda = LSI->Lambda;
+  QualType FieldType = S.getLambdaCaptureFieldType(Type, ByRef);
+
   // Build the non-static data member.
   FieldDecl *Field
     = FieldDecl::Create(S.Context, Lambda, Loc, Loc, 0, FieldType,
@@ -9715,20 +9716,20 @@
   return Result;
 }
 
-// Check if the variable needs to be captured; if so, try to perform
-// the capture.
-// FIXME: Add support for explicit captures.
-void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,
-                         TryCaptureKind Kind) {
+bool Sema::canCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit,
+                              bool Diagnose, QualType &Type, 
+                              unsigned &FunctionScopesIndex, bool &Nested) {
+  Type = Var->getType();
+  FunctionScopesIndex = FunctionScopes.size() - 1;
+  Nested = false;
+  
   DeclContext *DC = CurContext;
-  if (var->getDeclContext() == DC) return;
-  if (!var->hasLocalStorage()) return;
+  if (Var->getDeclContext() == DC) return false;
+  if (!Var->hasLocalStorage()) return false;
 
-  // Actually try to capture it.
-  QualType type = var->getType();
-  bool Nested = false;
+  bool HasBlocksAttr = Var->hasAttr<BlocksAttr>();
 
-  unsigned functionScopesIndex = FunctionScopes.size() - 1;
+  // Figure out whether we can capture the variable.
   do {
     // Only block literals and lambda expressions can capture; other
     // scopes don't work.
@@ -9736,84 +9737,125 @@
     if (isa<BlockDecl>(DC))
       ParentDC = DC->getParent();
     else if (isa<CXXMethodDecl>(DC) &&
+             cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
              cast<CXXRecordDecl>(DC->getParent())->isLambda())
       ParentDC = DC->getParent()->getParent();
-    else
-      return diagnoseUncapturableValueReference(*this, loc, var, DC);
+    else {
+      if (Diagnose)
+        diagnoseUncapturableValueReference(*this, Loc, Var, DC);
+      return false;
+    }
 
     CapturingScopeInfo *CSI =
-      cast<CapturingScopeInfo>(FunctionScopes[functionScopesIndex]);
+      cast<CapturingScopeInfo>(FunctionScopes[FunctionScopesIndex]);
 
     // Check whether we've already captured it.
-    if (CSI->CaptureMap.count(var)) {
+    if (CSI->CaptureMap.count(Var)) {
       // If we found a capture, any subcaptures are nested
       Nested = true;
 
-      if (shouldAddConstForScope(CSI, var))
-        type.addConst();
+      if (shouldAddConstForScope(CSI, Var))
+        Type.addConst();
       break;
     }
 
-    functionScopesIndex--;
-    DC = ParentDC;
-  } while (var->getDeclContext() != DC);
-
-  bool hasBlocksAttr = var->hasAttr<BlocksAttr>();
-
-  for (unsigned i = functionScopesIndex + 1,
-                e = FunctionScopes.size(); i != e; ++i) {
-    CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[i]);
-    bool isBlock = isa<BlockScopeInfo>(CSI);
-    bool isLambda = isa<LambdaScopeInfo>(CSI);
+    bool IsBlock = isa<BlockScopeInfo>(CSI);
+    bool IsLambda = isa<LambdaScopeInfo>(CSI);
 
     // Lambdas are not allowed to capture unnamed variables
     // (e.g. anonymous unions).
     // FIXME: The C++11 rule don't actually state this explicitly, but I'm
     // assuming that's the intent.
-    if (isLambda && !var->getDeclName()) {
-      Diag(loc, diag::err_lambda_capture_anonymous_var);
-      Diag(var->getLocation(), diag::note_declared_at);
-      return;
+    if (IsLambda && !Var->getDeclName()) {
+      if (Diagnose) {
+        Diag(Loc, diag::err_lambda_capture_anonymous_var);
+        Diag(Var->getLocation(), diag::note_declared_at);
+      }
+      return false;
     }
 
     // Prohibit variably-modified types; they're difficult to deal with.
-    if (type->isVariablyModifiedType()) {
-      if (isBlock)
-        Diag(loc, diag::err_ref_vm_type);
-      else
-        Diag(loc, diag::err_lambda_capture_vm_type) << var->getDeclName();
-      Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName();
-      return;
+    if (Type->isVariablyModifiedType()) {
+      if (Diagnose) {
+        if (IsBlock)
+          Diag(Loc, diag::err_ref_vm_type);
+        else
+          Diag(Loc, diag::err_lambda_capture_vm_type) << Var->getDeclName();
+        Diag(Var->getLocation(), diag::note_previous_decl) 
+          << Var->getDeclName();
+      }
+      return false;
     }
 
     // Blocks are not allowed to capture arrays.
-    if (isBlock && type->isArrayType()) {
-      Diag(loc, diag::err_ref_array_type);
-      Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName();
-      return;
+    if (IsBlock && Type->isArrayType()) {
+      if (Diagnose) {
+        Diag(Loc, diag::err_ref_array_type);
+        Diag(Var->getLocation(), diag::note_previous_decl) 
+          << Var->getDeclName();
+      }
+      return false;
     }
 
     // Lambdas are not allowed to capture __block variables; they don't
     // support the expected semantics.
-    if (isLambda && hasBlocksAttr) {
-      Diag(loc, diag::err_lambda_capture_block) << var->getDeclName();
-      Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName();
-      return;
+    if (IsLambda && HasBlocksAttr) {
+      if (Diagnose) {
+        Diag(Loc, diag::err_lambda_capture_block) 
+          << Var->getDeclName();
+        Diag(Var->getLocation(), diag::note_previous_decl) 
+          << Var->getDeclName();
+      }
+      return false;
+    }
+
+    if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) {
+      // No capture-default
+      if (Diagnose) {
+        Diag(Loc, diag::err_lambda_impcap) << Var->getDeclName();
+        Diag(Var->getLocation(), diag::note_previous_decl) 
+          << Var->getDeclName();
+        Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(),
+             diag::note_lambda_decl);
+      }
+      return false;
     }
 
+    FunctionScopesIndex--;
+    DC = ParentDC;
+    Explicit = false;
+  } while (!Var->getDeclContext()->Equals(DC));
+
+  ++FunctionScopesIndex;
+  return !Type->isVariablyModifiedType();
+}
+
+// Check if the variable needs to be captured; if so, try to perform
+// the capture.
+void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,
+                         TryCaptureKind Kind) {
+  QualType type;
+  unsigned functionScopesIndex;
+  bool Nested;
+  // Determine whether we can capture this variable, and where to
+  // start capturing.
+  if (!canCaptureVariable(var, loc, /*Explicit=*/Kind != TryCapture_Implicit,
+                          /*Diagnose=*/true, type, functionScopesIndex, Nested))
+    return;
+
+  bool hasBlocksAttr = var->hasAttr<BlocksAttr>();
+
+  for (unsigned i = functionScopesIndex,
+                e = FunctionScopes.size(); i != e; ++i) {
+    CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[i]);
+    bool isLambda = isa<LambdaScopeInfo>(CSI);
+
     bool byRef;
     bool isInnermostCapture = (i == e - 1);
     if (isInnermostCapture && Kind == TryCapture_ExplicitByVal) {
       byRef = false;
     } else if (isInnermostCapture && Kind == TryCapture_ExplicitByRef) {
       byRef = true;
-    } else if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) {
-      // No capture-default
-      Diag(loc, diag::err_lambda_impcap) << var->getDeclName();
-      Diag(var->getLocation(), diag::note_previous_decl) << var->getDeclName();
-      Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(),
-           diag::note_lambda_decl);
-      return;
     } else if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval) {
       // capture-default '='
       byRef = false;

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=150347&r1=150346&r2=150347&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Sun Feb 12 12:42:33 2012
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Template.h"
 #include "clang/Basic/OpenCL.h"
@@ -4368,12 +4369,98 @@
   return Context.getTypeOfExprType(E);
 }
 
+/// getDecltypeForExpr - Given an expr, will return the decltype for
+/// that expression, according to the rules in C++11
+/// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18.
+static QualType getDecltypeForExpr(Sema &S, Expr *E) {
+  if (E->isTypeDependent())
+    return S.Context.DependentTy;
+
+  // If e is an id expression or a class member access, decltype(e) is defined
+  // as the type of the entity named by e.
+  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+    if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl()))
+      return VD->getType();
+  }
+  if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+    if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+      return FD->getType();
+  }
+  // If e is a function call or an invocation of an overloaded operator,
+  // (parentheses around e are ignored), decltype(e) is defined as the
+  // return type of that function.
+  if (const CallExpr *CE = dyn_cast<CallExpr>(E->IgnoreParens()))
+    return CE->getCallReturnType();
+
+  // C++11 [expr.lambda.prim]p18:
+  //   Every occurrence of decltype((x)) where x is a possibly
+  //   parenthesized id-expression that names an entity of automatic
+  //   storage duration is treated as if x were transformed into an
+  //   access to a corresponding data member of the closure type that
+  //   would have been declared if x were an odr-use of the denoted
+  //   entity.
+  using namespace sema;
+  if (S.getCurLambda()) {
+    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 = E->getType();
+
+  // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is
+  // defined as T&, otherwise decltype(e) is defined as T.
+  if (E->isLValue())
+    T = S.Context.getLValueReferenceType(T);
+
+  return T;
+}
+
 QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) {
   ExprResult ER = CheckPlaceholderExpr(E);
   if (ER.isInvalid()) return QualType();
   E = ER.take();
   
-  return Context.getDecltypeType(E);
+  return Context.getDecltypeType(E, getDecltypeForExpr(*this, E));
 }
 
 QualType Sema::BuildUnaryTransformType(QualType BaseType,

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=150347&r1=150346&r2=150347&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Sun Feb 12 12:42:33 2012
@@ -3928,8 +3928,10 @@
     return Context.getTypeOfType(UnderlyingType);
   }
 
-  case TYPE_DECLTYPE:
-    return Context.getDecltypeType(ReadExpr(*Loc.F));
+  case TYPE_DECLTYPE: {
+    QualType UnderlyingType = readType(*Loc.F, Record, Idx);
+    return Context.getDecltypeType(ReadExpr(*Loc.F), UnderlyingType);
+  }
 
   case TYPE_UNARY_TRANSFORM: {
     QualType BaseType = readType(*Loc.F, Record, Idx);

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=150347&r1=150346&r2=150347&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Sun Feb 12 12:42:33 2012
@@ -222,6 +222,7 @@
 }
 
 void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) {
+  Writer.AddTypeRef(T->getUnderlyingType(), Record);
   Writer.AddStmt(T->getUnderlyingExpr());
   Code = TYPE_DECLTYPE;
 }

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp?rev=150347&r1=150346&r2=150347&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp Sun Feb 12 12:42:33 2012
@@ -65,11 +65,11 @@
     void work(int n) { // expected-note{{declared here}}
       int m = n*n;
       int j = 40; // expected-note{{declared here}}
-      auto m3 = [this,m] { // expected-note 2{{lambda expression begins here}}
+      auto m3 = [this,m] { // expected-note 3{{lambda expression begins here}}
         auto m4 = [&,j] { // expected-error{{variable 'j' cannot be implicitly captured in a lambda with no capture-default specified}}
           int x = n; // expected-error{{variable 'n' cannot be implicitly captured in a lambda with no capture-default specified}}
           x += m;
-          x += i; // expected-error{{reference to local variable 'i' declared in enclosing function 'f1'}}
+          x += i; // expected-error{{variable 'i' cannot be implicitly captured in a lambda with no capture-default specified}}
           x += f;
         };
       };

Added: 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=150347&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp Sun Feb 12 12:42:33 2012
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+
+template<typename T, typename U>
+struct is_same {
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+  static const bool value = true;
+};
+
+void f3() {
+  float x, &r = x;
+  int i;
+  int &ir = i;
+  const int &irc = i;
+
+  [=,&irc,&ir] {
+    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, 
+                  "should be const int&");
+    static_assert(is_same<decltype((irc)), const int&>::value, 
+                  "should be const int&");
+  }();
+
+  [=] {
+    [=] () mutable {
+      static_assert(is_same<decltype(x), float>::value, "should be float");
+      static_assert(is_same<decltype((x)), const float&>::value, 
+                    "should be const float&");
+    }();
+  }();
+}

Propchange: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/SemaCXX/lambda-expressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/lambda-expressions.cpp?rev=150347&r1=150346&r2=150347&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/lambda-expressions.cpp (original)
+++ cfe/trunk/test/SemaCXX/lambda-expressions.cpp Sun Feb 12 12:42:33 2012
@@ -72,7 +72,8 @@
 
     int f[10]; // expected-note {{declared}}
     [&]() { return f[2]; };  
-    (void) ^{ return []() { return f[2]; }; }; // expected-error {{cannot refer to declaration with an array type inside block}} 
+    (void) ^{ return []() { return f[2]; }; }; // expected-error {{variable 'f' cannot be implicitly captured in a lambda with no capture-default specified}} \
+    // expected-note{{lambda expression begins here}}
 
     struct G { G(); G(G&); int a; }; // expected-note 6 {{not viable}}
     G g;





More information about the cfe-commits mailing list