[clang] f43859a - PR45000: Let Sema::SubstParmVarDecl handle default args of lambdas in initializers

Aaron Puchert via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 22 13:39:14 PDT 2020


Author: Aaron Puchert
Date: 2020-04-22T22:37:21+02:00
New Revision: f43859a099fa3587123717be941fa63ba8d0d4f2

URL: https://github.com/llvm/llvm-project/commit/f43859a099fa3587123717be941fa63ba8d0d4f2
DIFF: https://github.com/llvm/llvm-project/commit/f43859a099fa3587123717be941fa63ba8d0d4f2.diff

LOG: PR45000: Let Sema::SubstParmVarDecl handle default args of lambdas in initializers

Summary:
We extend the behavior for local functions and methods of local classes
to lambdas in variable initializers. The initializer is not a separate
scope, but we treat it as such.

We also remove the (faulty) instantiation of default arguments in
TreeTransform::TransformLambdaExpr, because it doesn't do proper
initialization, and if it did, we would do it twice (and thus also emit
eventual errors twice).

Reviewed By: rsmith

Differential Revision: https://reviews.llvm.org/D76038

Added: 
    

Modified: 
    clang/include/clang/AST/DeclBase.h
    clang/lib/AST/DeclBase.cpp
    clang/lib/Sema/SemaTemplateInstantiate.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/lib/Sema/TreeTransform.h
    clang/test/SemaCXX/vartemplate-lambda.cpp
    clang/test/SemaTemplate/instantiate-local-class.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index b48f7e4f9308..91875377679d 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -869,14 +869,15 @@ class alignas(8) Decl {
     return getParentFunctionOrMethod() == nullptr;
   }
 
-  /// Returns true if this declaration lexically is inside a function.
-  /// It recognizes non-defining declarations as well as members of local
-  /// classes:
+  /// Returns true if this declaration is lexically inside a function or inside
+  /// a variable initializer. It recognizes non-defining declarations as well
+  /// as members of local classes:
   /// \code
   ///     void foo() { void bar(); }
   ///     void foo2() { class ABC { void bar(); }; }
+  ///     inline int x = [](){ return 0; };
   /// \endcode
-  bool isLexicallyWithinFunctionOrMethod() const;
+  bool isInLocalScope() const;
 
   /// If this decl is defined inside a function/method/block it returns
   /// the corresponding DeclContext, otherwise it returns null.

diff  --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 8a18de1e8248..2aab53f4fa90 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -332,13 +332,16 @@ void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
   }
 }
 
-bool Decl::isLexicallyWithinFunctionOrMethod() const {
+bool Decl::isInLocalScope() const {
   const DeclContext *LDC = getLexicalDeclContext();
   while (true) {
     if (LDC->isFunctionOrMethod())
       return true;
     if (!isa<TagDecl>(LDC))
       return false;
+    if (const auto *CRD = dyn_cast<CXXRecordDecl>(LDC))
+      if (CRD->isLambda())
+        return true;
     LDC = LDC->getLexicalParent();
   }
   return false;

diff  --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index e2b3ebba6bbe..4b6b92ccab2c 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2380,7 +2380,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
     UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm);
   } else if (Expr *Arg = OldParm->getDefaultArg()) {
     FunctionDecl *OwningFunc = cast<FunctionDecl>(OldParm->getDeclContext());
-    if (OwningFunc->isLexicallyWithinFunctionOrMethod()) {
+    if (OwningFunc->isInLocalScope()) {
       // Instantiate default arguments for methods of local classes (DR1484)
       // and non-defining declarations.
       Sema::ContextRAII SavedContext(*this, OwningFunc);

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 551517581063..a6541dabe6b2 100755
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4363,7 +4363,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
         EPI.ExceptionSpec.Type != EST_None &&
         EPI.ExceptionSpec.Type != EST_DynamicNone &&
         EPI.ExceptionSpec.Type != EST_BasicNoexcept &&
-        !Tmpl->isLexicallyWithinFunctionOrMethod()) {
+        !Tmpl->isInLocalScope()) {
       FunctionDecl *ExceptionSpecTemplate = Tmpl;
       if (EPI.ExceptionSpec.Type == EST_Uninstantiated)
         ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate;

diff  --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index abde968bed8c..da6ff8e5cea8 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -12219,19 +12219,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
 
   LSI->CallOperator = NewCallOperator;
 
-  for (unsigned I = 0, NumParams = NewCallOperator->getNumParams();
-       I != NumParams; ++I) {
-    auto *P = NewCallOperator->getParamDecl(I);
-    if (P->hasUninstantiatedDefaultArg()) {
-      EnterExpressionEvaluationContext Eval(
-          getSema(),
-          Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed, P);
-      ExprResult R = getDerived().TransformExpr(
-          E->getCallOperator()->getParamDecl(I)->getDefaultArg());
-      P->setDefaultArg(R.get());
-    }
-  }
-
   getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
   getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});
 

diff  --git a/clang/test/SemaCXX/vartemplate-lambda.cpp b/clang/test/SemaCXX/vartemplate-lambda.cpp
index 6744968bcc4d..b17c9bb8dcb9 100644
--- a/clang/test/SemaCXX/vartemplate-lambda.cpp
+++ b/clang/test/SemaCXX/vartemplate-lambda.cpp
@@ -4,7 +4,12 @@ template <class> auto fn0 = [] {};
 template <typename> void foo0() { fn0<char>(); }
 
 template<typename T> auto fn1 = [](auto a) { return a + T(1); };
-template<typename T> auto v1 = [](int a = T(1)) { return a; }();
+template<typename T> auto v1 = [](int a = T()) { return a; }();
+// expected-error at -1{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}}
+// expected-error at -2{{no matching function for call}}
+// expected-note at -3{{passing argument to parameter 'a' here}}
+// expected-note at -4{{candidate function not viable}}
+// expected-note at -5{{conversion candidate of type 'int (*)(int)'}}
 
 struct S {
   template<class T>
@@ -16,6 +21,7 @@ int foo2() {
   X a = 0x61;
   fn1<char>(a);
   (void)v1<int>;
+  (void)v1<int *>; // expected-note{{in instantiation of variable template specialization 'v1' requested here}}
   (void)S::t<int>; // expected-note{{in instantiation of static data member 'S::t<int>' requested here}}
   return 0;
 }

diff  --git a/clang/test/SemaTemplate/instantiate-local-class.cpp b/clang/test/SemaTemplate/instantiate-local-class.cpp
index eaff4c4bbc8d..550c59d61778 100644
--- a/clang/test/SemaTemplate/instantiate-local-class.cpp
+++ b/clang/test/SemaTemplate/instantiate-local-class.cpp
@@ -486,3 +486,16 @@ namespace anon_union_default_member_init {
   }
   void g() { f<int>(); }
 }
+
+namespace PR45000 {
+  template <typename T>
+  void f(int x = [](T x = nullptr) -> int { return x; }());
+  // expected-error at -1 {{cannot initialize a parameter of type 'int' with an rvalue of type 'nullptr_t'}}
+  // expected-note at -2 {{passing argument to parameter 'x' here}}
+  // expected-error at -3 {{no matching function for call}}
+  // expected-note at -4 {{candidate function not viable: requires single argument 'x', but no arguments were provided}}
+  // expected-note at -5 {{conversion candidate of type 'auto (*)(int) -> int'}}
+
+  void g() { f<int>(); }
+  // expected-note at -1 {{in instantiation of default function argument expression for 'f<int>' required here}}
+}


        


More information about the cfe-commits mailing list