]> granicus.if.org Git - clang/commitdiff
Fix computation of linkage within nested lambdas.
authorFaisal Vali <faisalv@yahoo.com>
Sun, 29 Sep 2013 20:00:15 +0000 (20:00 +0000)
committerFaisal Vali <faisalv@yahoo.com>
Sun, 29 Sep 2013 20:00:15 +0000 (20:00 +0000)
 When nested lambdas are used in NSDMI's - this prevents infinite recursion.

See http://llvm-reviews.chandlerc.com/D1783 for Doug's approval regarding the code, and then request for some tests.

[On a related note, I need this patch so as to pass tests of transformations of nested lambdas returned from member functions]

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

lib/AST/Decl.cpp
test/CodeGenCXX/lambda-expressions-nested-linkage.cpp [new file with mode: 0644]
test/SemaCXX/lambda-expressions.cpp

index 57bf94c0f0beebf62b0c019fcaa720842722b216..a2bb440dbe7e6327b44cc8ed3fd9bc13fe6c5297 100644 (file)
@@ -1004,10 +1004,8 @@ static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl,
     else
       return getLVForDecl(cast<NamedDecl>(ContextDecl), computation);
   }
-
   if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
     return getLVForDecl(ND, computation);
-
   return LinkageInfo::external();
 }
 
@@ -1092,6 +1090,19 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
                      LV.isVisibilityExplicit());
 }
 
+static inline const CXXRecordDecl*
+getOutermostEnclosingLambda(const CXXRecordDecl *Record) {
+  const CXXRecordDecl *Ret = Record;
+  while (Record && Record->isLambda()) {
+    Ret = Record;
+    if (!Record->getParent()) break;
+    // Get the Containing Class of this Lambda Class
+    Record = dyn_cast_or_null<CXXRecordDecl>(
+      Record->getParent()->getParent());
+  }
+  return Ret;
+}
+
 static LinkageInfo computeLVForDecl(const NamedDecl *D,
                                     LVComputationKind computation) {
   // Objective-C: treat all Objective-C declarations as having external
@@ -1122,9 +1133,24 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D,
           return LinkageInfo::internal();
         }
 
-        // This lambda has its linkage/visibility determined by its owner.
-        return getLVForClosure(D->getDeclContext()->getRedeclContext(),
-                               Record->getLambdaContextDecl(), computation);
+        // This lambda has its linkage/visibility determined:
+        //  - either by the outermost lambda if that lambda has no mangling 
+        //    number. 
+        //  - or by the parent of the outer most lambda
+        // This prevents infinite recursion in settings such as nested lambdas 
+        // used in NSDMI's, for e.g. 
+        //  struct L {
+        //    int t{};
+        //    int t2 = ([](int a) { return [](int b) { return b; };})(t)(t);    
+        //  };
+        const CXXRecordDecl *OuterMostLambda = 
+            getOutermostEnclosingLambda(Record);
+        if (!OuterMostLambda->getLambdaManglingNumber())
+          return LinkageInfo::internal();
+        
+        return getLVForClosure(
+                  OuterMostLambda->getDeclContext()->getRedeclContext(),
+                  OuterMostLambda->getLambdaContextDecl(), computation);
       }
       
       break;
diff --git a/test/CodeGenCXX/lambda-expressions-nested-linkage.cpp b/test/CodeGenCXX/lambda-expressions-nested-linkage.cpp
new file mode 100644 (file)
index 0000000..d763d41
--- /dev/null
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fblocks -emit-llvm -o - %s -fexceptions -std=c++11 | FileCheck %s
+
+// CHECK-LABEL: define void @_ZN19non_inline_function3fooEv()
+// CHECK-LABEL: define internal void @"_ZZN19non_inline_function3fooEvENK3$_0clEi"
+// CHECK-LABEL: define internal signext i8 @"_ZZZN19non_inline_function3fooEvENK3$_0clEiENKUlcE_clEc"
+namespace non_inline_function {
+void foo() {
+  auto L = [](int a) {
+    return [](char b) {
+     return b;
+    };
+  };
+  L(3)('a');
+}
+}
+// CHECK-LABEL: define linkonce_odr i32 @_ZN15inline_function3fooEv
+// CHECK-LABEL: define linkonce_odr void @_ZZN15inline_function3fooEvENKUliE_clEi
+// CHECK-LABEL: define linkonce_odr signext i8 @_ZZZN15inline_function3fooEvENKUliE_clEiENKUlcE_clEc
+namespace inline_function {
+inline int foo() {
+  auto L = [](int a) {
+    return [](char b) {
+     return b;
+    };
+  };
+  L(3)('a');
+}
+int use = foo();
+}
+
+// CHECK-LABEL: define linkonce_odr void @_ZN12non_template1LC1Ev
+// CHECK-LABEL: define linkonce_odr void @_ZNK12non_template1L1tMUliE_clEi(%class.anon
+// CHECK-LABEL: define linkonce_odr i32 @_ZZNK12non_template1L1tMUliE_clEiENKUliE_clEi(%class.anon
+namespace non_template {
+  struct L {
+    int t = ([](int a) { return [](int b) { return b; };})(2)(3);    
+  };
+  L l; 
+}
+
+// CHECK-LABEL: define linkonce_odr void @_ZN32lambdas_in_NSDMIs_template_class1LIiEC2Ev
+// CHECK-LABEL: define linkonce_odr void @_ZNK32lambdas_in_NSDMIs_template_class1LIiEUliE_clEi(%class.anon
+// CHECK-LABEL: linkonce_odr i32 @_ZZNK32lambdas_in_NSDMIs_template_class1LIiEUliE_clEiENKUliE_clEi(%class.anon
+namespace lambdas_in_NSDMIs_template_class {
+template<class T>
+struct L {
+    T t2 = ([](int a) { return [](int b) { return b; };})(T{})(T{});    
+};
+L<int> l;
+}
+
+
+
index e8e2eb612a0576786deb278a142c4ae12236070b..e2904247c4b440ab98bb770d7cc9c1c332600fd0 100644 (file)
@@ -265,3 +265,21 @@ namespace TypeDeduction {
 #endif
   }
 }
+
+
+namespace lambdas_in_NSDMIs {
+  template<class T>
+  struct L {
+      T t{};
+      T t2 = ([](int a) { return [](int b) { return b; };})(t)(t);    
+  };
+  L<int> l; 
+  
+  namespace non_template {
+    struct L {
+      int t = 0;
+      int t2 = ([](int a) { return [](int b) { return b; };})(t)(t);    
+    };
+    L l; 
+  }
+}
\ No newline at end of file