[PATCH] Fix for PR 18052 - lambdas within NSDMI's and default arguments in nested classes

Faisal Vali faisalv at yahoo.com
Wed Dec 4 12:12:50 PST 2013


Hi doug.gregor, rsmith,

Clang currently croaks on the following:
  struct X1 {
    struct X2 {
      int L = ([] (int i) { return i; })(2);
    };
  };

asserting that the containing lexical context of the lambda is not Sema's cur context, when pushing the lambda's decl context on.

This occurs because getContainingDC always returns the non-nested class even for inline member functions of nested classes (to account for delayed parsing of their bodies).  For lambda's call operator we have getContainingDC return the nested class.  This fixes the bug.

I will say that this entire business of getContainingDC returning the non-nested class for member functions and the nested class for lambdas seems fragile and smelly ...

Any better ideas on how to address this?

Thanks!

http://llvm-reviews.chandlerc.com/D2331

Files:
  lib/Sema/SemaDecl.cpp
  test/SemaCXX/cxx1y-generic-lambdas.cpp

Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -871,6 +871,7 @@
   // finished parsing the top-level class, so the top-level class is
   // the context we'll need to return to.
   if (isa<FunctionDecl>(DC)) {
+    const bool IsLambdaCallOperator = isLambdaCallOperator(DC);
     DC = DC->getLexicalParent();
 
     // A function not defined within a class will always return to its
@@ -878,6 +879,18 @@
     if (!isa<CXXRecordDecl>(DC))
       return DC;
 
+    // A Lambda call operator whose parent is a class must not be treated 
+    // as an inline member function.  A Lambda can be used legally
+    // either as an in-class member initializer or a default argument.  These
+    // are parsed once the class has been marked complete and so the containing
+    // context would be the nested class (when the lambda is defined in one);
+    // If the class is not complete, then the lambda is being used in an 
+    // ill-formed fashion (such as to specify the width of a bit-field, or
+    // in an array-bound) - in which case we still want to return the 
+    // lexically containing DC (which could be a nested class). 
+    if (IsLambdaCallOperator) 
+      return DC;
+  
     // A C++ inline method/friend is parsed *after* the topmost class
     // it was declared in is fully parsed ("complete");  the topmost
     // class is the context we need to return to.
Index: test/SemaCXX/cxx1y-generic-lambdas.cpp
===================================================================
--- test/SemaCXX/cxx1y-generic-lambdas.cpp
+++ test/SemaCXX/cxx1y-generic-lambdas.cpp
@@ -844,5 +844,65 @@
   [=] { v.size(); };
 }
 
+}
 
-}
\ No newline at end of file
+namespace inclass_lambdas_within_nested_classes {
+namespace ns1 {
+
+struct X1 {  
+  struct X2 {
+    enum { E = [](auto i) { return i; }(3) }; //expected-error{{inside of a constant expression}}\
+                                          //expected-error{{not an integral constant}}
+    int L = ([] (int i) { return i; })(2);
+    void foo(int i = ([] (int i) { return i; })(2)) { }
+    int B : ([](int i) { return i; })(3); //expected-error{{inside of a constant expression}}\
+                                          //expected-error{{not an integral constant}}
+    int arr[([](int i) { return i; })(3)]; //expected-error{{inside of a constant expression}}\
+                                           //expected-error{{must have a constant size}}
+    int (*fp)(int) = [](int i) { return i; };
+    void fooptr(int (*fp)(char) = [](char c) { return 0; }) { }
+    int L2 = ([](auto i) { return i; })(2);
+    void fooG(int i = ([] (auto i) { return i; })(2)) { }
+    int BG : ([](auto i) { return i; })(3); //expected-error{{inside of a constant expression}}  \
+                                             //expected-error{{not an integral constant}}
+    int arrG[([](auto i) { return i; })(3)]; //expected-error{{inside of a constant expression}}\
+                                           //expected-error{{must have a constant size}}
+    int (*fpG)(int) = [](auto i) { return i; };
+    void fooptrG(int (*fp)(char) = [](auto c) { return 0; }) { }
+  };
+};
+} //end ns
+
+namespace ns2 {
+struct X1 {  
+  template<class T>
+  struct X2 {
+    int L = ([] (T i) { return i; })(2);
+    void foo(int i = ([] (int i) { return i; })(2)) { }
+    int B : ([](T i) { return i; })(3); //expected-error{{inside of a constant expression}}\
+                                          //expected-error{{not an integral constant}}
+    int arr[([](T i) { return i; })(3)]; //expected-error{{inside of a constant expression}}\
+                                           //expected-error{{must have a constant size}}
+    int (*fp)(T) = [](T i) { return i; };
+    void fooptr(T (*fp)(char) = [](char c) { return 0; }) { }
+    int L2 = ([](auto i) { return i; })(2);
+    void fooG(T i = ([] (auto i) { return i; })(2)) { }
+    int BG : ([](auto i) { return i; })(3); //expected-error{{not an integral constant}}
+    int arrG[([](auto i) { return i; })(3)]; //expected-error{{must have a constant size}}
+    int (*fpG)(T) = [](auto i) { return i; };
+    void fooptrG(T (*fp)(char) = [](auto c) { return 0; }) { }
+    template<class U = char> int fooG2(T (*fp)(U) = [](auto a) { return 0; }) { return 0; }
+    template<class U = char> int fooG3(T (*fp)(U) = [](auto a) { return 0; });
+  };
+};
+template<class T> 
+template<class U>
+int X1::X2<T>::fooG3(T (*fp)(U)) { return 0; } 
+X1::X2<int> x2; //expected-note 3{{in instantiation of}}
+int run1 = x2.fooG2();
+int run2 = x2.fooG3();
+} // end ns
+
+
+
+} //end ns inclass_lambdas_within_nested_classes
\ No newline at end of file
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D2331.1.patch
Type: text/x-patch
Size: 4772 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131204/58fcf967/attachment.bin>


More information about the cfe-commits mailing list