[clang] c56975e - Fix template instantiation of a non-dependent call to an inherited

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 6 19:20:36 PDT 2020


Author: Richard Smith
Date: 2020-04-06T19:20:30-07:00
New Revision: c56975e299e17a503066c98a3afaf02c5b231f9e

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

LOG: Fix template instantiation of a non-dependent call to an inherited
constructor with default arguments.

We used to try to rebuild the call as a call to the faked-up inherited
constructor, which is only a placeholder and lacks (for example) default
arguments. Instead, build the call by reference to the original
constructor.

In passing, add a note to say where a call that recursively uses a
default argument from within itself occurs. This is usually pretty
obvious, but still at least somewhat useful, and would have saved
significant debugging time for this particular bug.

Added: 
    

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaExpr.cpp
    clang/lib/Sema/TreeTransform.h
    clang/test/SemaCXX/default2.cpp
    clang/test/SemaTemplate/instantiate-init.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6ccb1c4af951..148f23f362dc 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3952,6 +3952,8 @@ def err_use_of_default_argument_to_function_declared_later : Error<
 def note_default_argument_declared_here : Note<
   "default argument declared here">;
 def err_recursive_default_argument : Error<"recursive evaluation of default argument">;
+def note_recursive_default_argument_used_here : Note<
+  "default argument used here">;
 
 def ext_param_promoted_not_compatible_with_prototype : ExtWarn<
   "%
diff {promoted type $ of K&R function parameter is not compatible with the "

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index b311aad84816..a4f9c22138ee 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -5284,6 +5284,7 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
   // If the default argument expression is not set yet, we are building it now.
   if (!Param->hasInit()) {
     Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD;
+    Diag(CallLoc, diag::note_recursive_default_argument_used_here);
     Param->setInvalidDecl();
     return true;
   }

diff  --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 1f88f9c57465..e9f4b11ca7bb 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3028,9 +3028,14 @@ class TreeTransform {
                                      bool RequiresZeroInit,
                              CXXConstructExpr::ConstructionKind ConstructKind,
                                      SourceRange ParenRange) {
+    // Reconstruct the constructor we originally found, which might be
+    // 
diff erent if this is a call to an inherited constructor.
+    CXXConstructorDecl *FoundCtor = Constructor;
+    if (Constructor->isInheritingConstructor())
+      FoundCtor = Constructor->getInheritedConstructor().getConstructor();
+
     SmallVector<Expr*, 8> ConvertedArgs;
-    if (getSema().CompleteConstructorCall(Constructor, Args, Loc,
-                                          ConvertedArgs))
+    if (getSema().CompleteConstructorCall(FoundCtor, Args, Loc, ConvertedArgs))
       return ExprError();
 
     return getSema().BuildCXXConstructExpr(Loc, T, Constructor,

diff  --git a/clang/test/SemaCXX/default2.cpp b/clang/test/SemaCXX/default2.cpp
index 8f77f300572b..4c8e8ce6941a 100644
--- a/clang/test/SemaCXX/default2.cpp
+++ b/clang/test/SemaCXX/default2.cpp
@@ -130,5 +130,8 @@ template <int I1 = I2, int I2 = 1> struct T {};  // expected-error-re {{use of u
 T<0, 1> t;
 
 struct PR28105 {
-  PR28105 (int = 0, int = 0, PR28105 = 0);  // expected-error{{recursive evaluation of default argument}}
+  PR28105 (int = 0, int = 0,
+      PR28105  // expected-error{{recursive evaluation of default argument}}
+      =
+      0); // expected-note {{default argument used here}}
 };

diff  --git a/clang/test/SemaTemplate/instantiate-init.cpp b/clang/test/SemaTemplate/instantiate-init.cpp
index 99b29c77d55a..6a4f65095dd5 100644
--- a/clang/test/SemaTemplate/instantiate-init.cpp
+++ b/clang/test/SemaTemplate/instantiate-init.cpp
@@ -1,5 +1,13 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
 
+namespace std {
+  template<typename T> struct initializer_list {
+    T *p;
+    __SIZE_TYPE__ n;
+    initializer_list(T*, __SIZE_TYPE__);
+  };
+}
+
 struct X0 { // expected-note 8{{candidate}}
   X0(int*, float*); // expected-note 4{{candidate}}
 };
@@ -158,3 +166,15 @@ namespace InitListUpdate {
   void g(AA, AA);
   void h() { f<1, 2>(); } // expected-note {{instantiation of}}
 }
+
+namespace RebuildStdInitList {
+  struct A { A(std::initializer_list<int>, int = 0) {} };
+  struct B : A { using A::A; };
+  struct PES { PES(B); };
+
+  // Check we can rebuild the use of the default argument here. This requires
+  // going to the original (base class) constructor, because we don't copy
+  // default arguments onto our fake derived class inherited constructors.
+  template<typename U> void f() { PES({1, 2, 3}); }
+  void g() { f<int>(); }
+}


        


More information about the cfe-commits mailing list