]> granicus.if.org Git - clang/commitdiff
Within the body of a lambda expression, decltype((x)) for an
authorDouglas Gregor <dgregor@apple.com>
Sun, 12 Feb 2012 18:42:33 +0000 (18:42 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sun, 12 Feb 2012 18:42:33 +0000 (18:42 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150347 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
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 [new file with mode: 0644]
test/SemaCXX/lambda-expressions.cpp

index 82570f594d4a1391cc64c20758bfc6ba86daffd5..7f1f7356e5250c86968b46a69151bb1b3ec72378 100644 (file)
@@ -876,7 +876,7 @@ public:
   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,
index dcc9fca3285cbe30683ceddae5ffb69b9b9903fc..29a07f3cb157280194636e3c7e59892858e2ddab 100644 (file)
@@ -3040,10 +3040,6 @@ public:
 /// 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:
index ea77ff49cb5980fb172ad38575d61131222f3f9b..1861e958ae6cce7fa2fd0a82bea6e56c17137768 100644 (file)
 namespace clang {
 
 class BlockDecl;
+class CXXMethodDecl;
 class IdentifierInfo;
 class LabelDecl;
 class ReturnStmt;
 class Scope;
 class SwitchStmt;
+class VarDecl;
 
 namespace sema {
 
index ce36d23706ef7af4d493446ac1fdc8635f7b9997..3333e56e71422121e116bb92dbbd0fc6080e05fc 100644 (file)
@@ -2282,6 +2282,34 @@ public:
   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
   };
index bb93a68d26550ea3daecd85c28534ec51cfd4680..cc651f9c9c5926bc3debfbc0ff2526d6c6bb3d35 100644 (file)
@@ -2913,44 +2913,13 @@ QualType ASTContext::getTypeOfType(QualType tofType) const {
   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 @@ QualType ASTContext::getDecltypeType(Expr *e) const {
       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);
index 556f97d858258b9c84bc7528e08afd511dc6154b..e15bac0b44766398b33fad46d830fc1e47f1be34 100644 (file)
@@ -1581,7 +1581,11 @@ QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) {
   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) {
index ce5956ae2f8e6db26cb6f469fc16cfc8fd320d89..9bd1074116ff31a87ecae01d8347f8a7699ad4d1 100644 (file)
@@ -9566,12 +9566,7 @@ static bool shouldAddConstForScope(CapturingScopeInfo *CSI, VarDecl *VD) {
   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 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
     //   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 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
   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 @@ void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,
     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;
index 7d9a33af11f75bc0d9ba27a53b9cc6d6fc83f183..a235872d8fabf458888fc494a34c296715b6868f 100644 (file)
@@ -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 @@ QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) {
   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,
index 312f5c718f0041473a2389f0f10a679b9b70238d..75b5d68ce65356695aa11c2a8e4e629f45c56ae7 100644 (file)
@@ -3928,8 +3928,10 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
     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);
index 5364aa83cb84028406cc8994cd9586da66e9760b..7a0fed720f83788a10311afb31c764ea5d719cec 100644 (file)
@@ -222,6 +222,7 @@ void ASTTypeWriter::VisitTypeOfType(const TypeOfType *T) {
 }
 
 void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) {
+  Writer.AddTypeRef(T->getUnderlyingType(), Record);
   Writer.AddStmt(T->getUnderlyingExpr());
   Code = TYPE_DECLTYPE;
 }
index fdf6c53633dbf9175d13279a2a97e73f27dfa592..e7eb5af891372ddf40d53a8eb73a03de54dcb895 100644 (file)
@@ -65,11 +65,11 @@ void f1(int i) { // expected-note{{declared here}}
     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;
         };
       };
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
new file mode 100644 (file)
index 0000000..561ead1
--- /dev/null
@@ -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&");
+    }();
+  }();
+}
index 1da57c6c726982a67f764f27e8341b1ff4442f39..afbf9a1fffc1f4a0fe6129462df90ae2c56975af 100644 (file)
@@ -72,7 +72,8 @@ namespace ImplicitCapture {
 
     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;