[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.cp

Eli Friedman eli.friedman at gmail.com
Tue Feb 21 12:15:14 PST 2012


On Tue, Feb 21, 2012 at 11:11 AM, Douglas Gregor <dgregor at apple.com> wrote:
> 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;

What exactly are the rules for odr-use marking inside a lambda in a
default argument, actually?

-Eli




More information about the cfe-commits mailing list