[cfe-commits] r151076 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/Sema/Sema.h lib/AST/DeclBase.cpp lib/AST/DeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaLambda.cpp lib/Serialization/ASTReaderDecl.cpp lib/Serialization/ASTWriter.cpp test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp

Douglas Gregor dgregor at apple.com
Tue Feb 21 11:11:17 PST 2012


Author: dgregor
Date: Tue Feb 21 13:11:17 2012
New Revision: 151076

URL: http://llvm.org/viewvc/llvm-project?rev=151076&view=rev
Log:
Improve our handling of lambda expressions that occur within default
arguments. There are two aspects to this:

  - Make sure that when marking the declarations referenced in a
  default argument, we don't try to mark local variables, both because
  it's a waste of time and because the semantics are wrong: we're not
  in a place where we could capture these variables again even if it
  did make sense.
  - When a lambda expression occurs in a default argument of a
  function template, make sure that the corresponding closure type is
  considered dependent, so that it will get properly instantiated. The
  second bit is a bit of a hack; to fix it properly, we may have to
  rearchitect our handling of default arguments, parsing them only
  after creating the function definition. However, I'd like to
  separate that work from the lambdas work.


Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/DeclBase.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaLambda.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=151076&r1=151075&r2=151076&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Feb 21 13:11:17 2012
@@ -560,18 +560,28 @@
   struct LambdaDefinitionData : public DefinitionData {
     typedef LambdaExpr::Capture Capture;
     
-    LambdaDefinitionData(CXXRecordDecl *D) 
-      : DefinitionData(D), NumCaptures(0), NumExplicitCaptures(0), 
-        ContextDecl(0), Captures(0) 
+    LambdaDefinitionData(CXXRecordDecl *D, bool Dependent) 
+      : DefinitionData(D), Dependent(Dependent), NumCaptures(0), 
+        NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), Captures(0) 
     {
       IsLambda = true;
     }
 
+    /// \brief Whether this lambda is known to be dependent, even if its
+    /// context isn't dependent.
+    /// 
+    /// A lambda with a non-dependent context can be dependent if it occurs
+    /// within the default argument of a function template, because the
+    /// lambda will have been created with the enclosing context as its
+    /// declaration context, rather than function. This is an unfortunate
+    /// artifact of having to parse the default arguments before 
+    unsigned Dependent : 1;
+    
     /// \brief The number of captures in this lambda.
     unsigned NumCaptures : 16;
 
     /// \brief The number of explicit captures in this lambda.
-    unsigned NumExplicitCaptures : 16;
+    unsigned NumExplicitCaptures : 15;
 
     /// \brief The number used to indicate this lambda expression for name 
     /// mangling in the Itanium C++ ABI.
@@ -689,7 +699,7 @@
                                IdentifierInfo *Id, CXXRecordDecl* PrevDecl=0,
                                bool DelayTypeCreation = false);
   static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC,
-                                     SourceLocation Loc);
+                                     SourceLocation Loc, bool DependentLambda);
   static CXXRecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
 
   bool isDynamicClass() const {
@@ -1478,6 +1488,21 @@
     return getLambdaData().ContextDecl;    
   }
   
+  /// \brief Determine whether this lambda expression was known to be dependent
+  /// at the time it was created, even if its context does not appear to be
+  /// dependent.
+  ///
+  /// This flag is a workaround for an issue with parsing, where default
+  /// arguments are parsed before their enclosing function declarations have
+  /// been created. This means that any lambda expressions within those
+  /// default arguments will have as their DeclContext the context enclosing
+  /// the function declaration, which may be non-dependent even when the
+  /// function declaration itself is dependent. This flag indicates when we
+  /// know that the lambda is dependent despite that.
+  bool isDependentLambda() const {
+    return isLambda() && getLambdaData().Dependent;
+  }
+  
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) {
     return K >= firstCXXRecord && K <= lastCXXRecord;

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=151076&r1=151075&r2=151076&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Feb 21 13:11:17 2012
@@ -2386,7 +2386,8 @@
   QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc);
   
   void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
-  void MarkDeclarationsReferencedInExpr(Expr *E);
+  void MarkDeclarationsReferencedInExpr(Expr *E, 
+                                        bool SkipLocalVariables = false);
 
   /// \brief Try to recover by turning the given expression into a
   /// call.  Returns true if recovery was attempted or an error was
@@ -3543,7 +3544,8 @@
   void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl);
 
   /// \brief Create a new lambda closure type.
-  CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange);
+  CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange,
+                                         bool KnownDependent = false);
   
   /// \brief Start the definition of a lambda expression.
   CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class,

Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=151076&r1=151075&r2=151076&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Tue Feb 21 13:11:17 2012
@@ -741,10 +741,14 @@
   if (isa<ClassTemplatePartialSpecializationDecl>(this))
     return true;
 
-  if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this))
+  if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) {
     if (Record->getDescribedClassTemplate())
       return true;
-
+    
+    if (Record->isDependentLambda())
+      return true;
+  }
+  
   if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) {
     if (Function->getDescribedFunctionTemplate())
       return true;

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=151076&r1=151075&r2=151076&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Feb 21 13:11:17 2012
@@ -83,11 +83,11 @@
 }
 
 CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
-                                           SourceLocation Loc) {
+                                           SourceLocation Loc, bool Dependent) {
   CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc,
                                            0, 0);
   R->IsBeingDefined = true;
-  R->DefinitionData = new (C) struct LambdaDefinitionData(R);
+  R->DefinitionData = new (C) struct LambdaDefinitionData(R, Dependent);
   C.getTypeDeclType(R, /*PrevDecl=*/0);
   return R;
 }

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=151076&r1=151075&r2=151076&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Feb 21 13:11:17 2012
@@ -3146,7 +3146,8 @@
   // We already type-checked the argument, so we know it works. 
   // Just mark all of the declarations in this potentially-evaluated expression
   // as being "referenced".
-  MarkDeclarationsReferencedInExpr(Param->getDefaultArg());
+  MarkDeclarationsReferencedInExpr(Param->getDefaultArg(),
+                                   /*SkipLocalVariables=*/true);
   return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param));
 }
 
@@ -10145,13 +10146,22 @@
   /// potentially-evaluated subexpressions as "referenced".
   class EvaluatedExprMarker : public EvaluatedExprVisitor<EvaluatedExprMarker> {
     Sema &S;
+    bool SkipLocalVariables;
     
   public:
     typedef EvaluatedExprVisitor<EvaluatedExprMarker> Inherited;
     
-    explicit EvaluatedExprMarker(Sema &S) : Inherited(S.Context), S(S) { }
+    EvaluatedExprMarker(Sema &S, bool SkipLocalVariables) 
+      : Inherited(S.Context), S(S), SkipLocalVariables(SkipLocalVariables) { }
     
     void VisitDeclRefExpr(DeclRefExpr *E) {
+      // If we were asked not to visit local variables, don't.
+      if (SkipLocalVariables) {
+        if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
+          if (VD->hasLocalStorage())
+            return;
+      }
+      
       S.MarkDeclRefReferenced(E);
     }
     
@@ -10193,6 +10203,10 @@
     }
     
     void VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+      // If we were asked not to visit local variables, don't.
+      if (SkipLocalVariables && E->getDecl()->hasLocalStorage())
+          return;
+
       S.MarkBlockDeclRefReferenced(E);
     }
     
@@ -10211,8 +10225,12 @@
 
 /// \brief Mark any declarations that appear within this expression or any
 /// potentially-evaluated subexpressions as "referenced".
-void Sema::MarkDeclarationsReferencedInExpr(Expr *E) {
-  EvaluatedExprMarker(*this).Visit(E);
+///
+/// \param SkipLocalVariables If true, don't mark local variables as 
+/// 'referenced'.
+void Sema::MarkDeclarationsReferencedInExpr(Expr *E, 
+                                            bool SkipLocalVariables) {
+  EvaluatedExprMarker(*this, SkipLocalVariables).Visit(E);
 }
 
 /// \brief Emit a diagnostic that describes an effect on the run-time behavior

Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=151076&r1=151075&r2=151076&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Tue Feb 21 13:11:17 2012
@@ -21,14 +21,16 @@
 using namespace clang;
 using namespace sema;
 
-CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange) {
+CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
+                                             bool KnownDependent) {
   DeclContext *DC = CurContext;
   while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
     DC = DC->getParent();
   
   // Start constructing the lambda class.
   CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, 
-                                                     IntroducerRange.getBegin());
+                                                     IntroducerRange.getBegin(),
+                                                     KnownDependent);
   DC->addDecl(Class);
   
   return Class;
@@ -142,7 +144,14 @@
 void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
                                         Declarator &ParamInfo,
                                         Scope *CurScope) {
-  CXXRecordDecl *Class = createLambdaClosureType(Intro.Range);
+  // Determine if we're within a context where we know that the lambda will
+  // be dependent, because there are template parameters in scope.
+  bool KnownDependent = false;
+  if (Scope *TmplScope = CurScope->getTemplateParamParent())
+    if (!TmplScope->decl_empty())
+      KnownDependent = true;
+  
+  CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, KnownDependent);
   
   // Determine the signature of the call operator.
   TypeSourceInfo *MethodTyInfo;

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=151076&r1=151075&r2=151076&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Tue Feb 21 13:11:17 2012
@@ -1107,6 +1107,7 @@
     typedef LambdaExpr::Capture Capture;
     CXXRecordDecl::LambdaDefinitionData &Lambda
       = static_cast<CXXRecordDecl::LambdaDefinitionData &>(Data);
+    Lambda.Dependent = Record[Idx++];
     Lambda.NumCaptures = Record[Idx++];
     Lambda.NumExplicitCaptures = Record[Idx++];
     Lambda.ManglingNumber = Record[Idx++];
@@ -1134,7 +1135,7 @@
     // allocate the appropriate DefinitionData structure.
     bool IsLambda = Record[Idx++];
     if (IsLambda)
-      D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D);
+      D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D, false);
     else
       D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
     

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=151076&r1=151075&r2=151076&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Feb 21 13:11:17 2012
@@ -4330,6 +4330,7 @@
   // Add lambda-specific data.
   if (Data.IsLambda) {
     CXXRecordDecl::LambdaDefinitionData &Lambda = D->getLambdaData();
+    Record.push_back(Lambda.Dependent);
     Record.push_back(Lambda.NumCaptures);
     Record.push_back(Lambda.NumExplicitCaptures);
     Record.push_back(Lambda.ManglingNumber);

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp?rev=151076&r1=151075&r2=151076&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp Tue Feb 21 13:11:17 2012
@@ -8,3 +8,9 @@
   void g4(int = ([=]{ return 0; })());
   void g5(int = ([]{ return sizeof i; })());
 }
+
+namespace lambda_in_default_args {
+  int f(int = [] () -> int { int n; return ++n; } ());
+  template<typename T> T g(T = [] () -> T { T n; return ++n; } ());
+  int k = f() + g<int>();
+}





More information about the cfe-commits mailing list