[PATCH] Try to fix PR16239

Wei Pan wei.pan at intel.com
Tue Jun 25 18:48:43 PDT 2013


wwwwpan added you to the CC list for the revision "Try to fix PR16239".

Hi rsmith, dblaikie,

- In this bug, Sema is performing a constructor initialization, and it's
  associated argument conversions invoke this constructor initialization
  again. This causes an infinite recursion.

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

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaInit.cpp
  test/SemaCXX/constructor.cpp

Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -266,6 +266,11 @@
   /// if Sema is already doing so, which would cause infinite recursions.
   bool IsBuildingRecoveryCallExpr;
 
+  /// \brief All constructors in construction. This is to detect if 
+  /// converting the arguments calls any constructor being constructed,
+  /// which leads to an infinite recursion.
+  llvm::SmallVector<CXXConstructorDecl *, 2> CtorsInConstruction;
+
   /// ExprNeedsCleanups - True if the current evaluation context
   /// requires cleanups to be run at its conclusion.
   bool ExprNeedsCleanups;
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -10147,6 +10147,13 @@
   else
     ConvertedArgs.reserve(NumArgs);
 
+  // Mark this constructor being constructed so that its argument construction
+  // should not call itself.
+  CXXConstructorDecl *Ctor = Constructor;
+  if (FunctionTemplateDecl *FuncTmpl = Ctor->getPrimaryTemplate())
+    Ctor = cast<CXXConstructorDecl>(FuncTmpl->getTemplatedDecl());
+  CtorsInConstruction.push_back(Ctor);
+
   VariadicCallType CallType = 
     Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
   SmallVector<Expr *, 8> AllArgs;
@@ -10165,6 +10172,9 @@
                                                         AllArgs.size()),
                        Proto, Loc);
 
+  // Cleanup once finished the constructor call.
+  CtorsInConstruction.pop_back();
+
   return Invalid;
 }
 
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -3008,7 +3008,15 @@
         SuppressUserConversions = true;
     }
 
-    if (!Constructor->isInvalidDecl() &&
+    // If Sema is already building this constructor call, then this constructor
+    // cannot be a candidate for initializing its arguments. Otherwise, this
+    // leads to an infinite recursion.
+    bool InConstruction =
+      S.CtorsInConstruction.end() != std::find(S.CtorsInConstruction.begin(),
+                                               S.CtorsInConstruction.end(),
+                                               Constructor);
+
+    if (!Constructor->isInvalidDecl() && !InConstruction &&
         (AllowExplicit || !Constructor->isExplicit()) &&
         (!OnlyListConstructors || S.isInitListConstructor(Constructor))) {
       if (ConstructorTmpl)
Index: test/SemaCXX/constructor.cpp
===================================================================
--- test/SemaCXX/constructor.cpp
+++ test/SemaCXX/constructor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s 
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s 
 typedef int INT;
 
 class Foo {
@@ -85,3 +85,34 @@
 
 A::S::~S() {}
 
+namespace PR16239 {
+struct Foo;
+struct Bar;
+
+struct Move2 {
+  Move2(Foo f); // expected-note {{passing argument to parameter 'f' here}}
+  Move2(Bar b); // expected-note {{passing argument to parameter 'b' here}}
+};
+
+struct Foo {
+  Foo(const Move2&);
+
+  Foo(Foo&); // expected-note {{candidate constructor not viable}}
+};
+
+struct Bar {
+  template <typename T = int>
+  Bar(const Move2&, T t = T());
+
+  Bar(Bar&); // expected-note {{candidate constructor not viable}}
+};
+
+Foo func_foo();
+Bar func_bar();
+
+void Baz() {
+  Foo f = func_foo(); // expected-error{{no matching constructor for initialization}}
+  Bar b = func_bar(); // expected-error{{no matching constructor for initialization}}
+}
+
+} // namespace
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D1038.1.patch
Type: text/x-patch
Size: 3675 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130625/ce0a4f69/attachment.bin>


More information about the cfe-commits mailing list