[clang] b5f2c4e - PR23029 / C++ DR2233: Allow expanded parameter packs to follow

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 2 13:49:08 PDT 2020


Author: Richard Smith
Date: 2020-06-02T13:48:59-07:00
New Revision: b5f2c4e45b8d54063051e6955cef0bbb7b6ab0f8

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

LOG: PR23029 / C++ DR2233: Allow expanded parameter packs to follow
parameters with default arguments.

Directly follow the wording by relaxing the AST invariant that all
parameters after one with a default arguemnt also have default
arguments, and removing the diagnostic on missing default arguments
on a pack-expanded parameter following a parameter with a default
argument.

Testing also revealed that we need to special-case explicit
specializations of templates with a pack following a parameter with a
default argument, as such explicit specializations are otherwise
impossible to write. The standard wording doesn't address this case; a
issue has been filed.

This exposed a bug where we would briefly consider a parameter to have
no default argument while we parse a delay-parsed default argument for
that parameter, which is also fixed.

Partially incorporates a patch by Raul Tambre.

Added: 
    clang/test/CXX/expr/expr.post/expr.call/p4.cpp

Modified: 
    clang/include/clang/AST/Decl.h
    clang/include/clang/Sema/Template.h
    clang/lib/AST/Decl.cpp
    clang/lib/AST/DeclCXX.cpp
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/lib/Sema/SemaExpr.cpp
    clang/lib/Sema/SemaOverload.cpp
    clang/lib/Sema/SemaTemplateInstantiate.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
    clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp
    clang/test/CXX/drs/dr0xx.cpp
    clang/test/CXX/drs/dr1xx.cpp
    clang/test/CXX/drs/dr22xx.cpp
    clang/test/CXX/drs/dr7xx.cpp
    clang/test/SemaCXX/abstract.cpp
    clang/test/SemaCXX/constant-expression-cxx11.cpp
    clang/test/SemaCXX/decl-init-ref.cpp
    clang/test/SemaCXX/implicit-exception-spec.cpp
    clang/test/SemaCXX/warn-bool-conversion.cpp
    clang/www/cxx_dr_status.html

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 2e1630827cce..185ba2f4b4c1 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2439,6 +2439,14 @@ class FunctionDecl : public DeclaratorDecl,
   /// parameters have default arguments (in C++).
   unsigned getMinRequiredArguments() const;
 
+  /// Determine whether this function has a single parameter, or multiple
+  /// parameters where all but the first have default arguments.
+  ///
+  /// This notion is used in the definition of copy/move constructors and
+  /// initializer list constructors. Note that, unlike getMinRequiredArguments,
+  /// parameter packs are not treated specially here.
+  bool hasOneParamOrDefaultArgs() const;
+
   /// Find the source location information for how the type of this function
   /// was written. May be absent (for example if the function was declared via
   /// a typedef) and may contain a 
diff erent type from that of the function

diff  --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 47d6143bdc9a..8166b6cf9b6f 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -422,6 +422,9 @@ class VarDecl;
     NamedDecl *
     getPartiallySubstitutedPack(const TemplateArgument **ExplicitArgs = nullptr,
                                 unsigned *NumExplicitArgs = nullptr) const;
+
+    /// Determine whether D is a pack expansion created in this scope.
+    bool isLocalPackExpansion(const Decl *D);
   };
 
   class TemplateDeclInstantiator

diff  --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index e6800073ee58..23547933b88b 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3264,13 +3264,27 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
   if (!getASTContext().getLangOpts().CPlusPlus)
     return getNumParams();
 
+  // Note that it is possible for a parameter with no default argument to
+  // follow a parameter with a default argument.
   unsigned NumRequiredArgs = 0;
-  for (auto *Param : parameters())
-    if (!Param->isParameterPack() && !Param->hasDefaultArg())
-      ++NumRequiredArgs;
+  unsigned MinParamsSoFar = 0;
+  for (auto *Param : parameters()) {
+    if (!Param->isParameterPack()) {
+      ++MinParamsSoFar;
+      if (!Param->hasDefaultArg())
+        NumRequiredArgs = MinParamsSoFar;
+    }
+  }
   return NumRequiredArgs;
 }
 
+bool FunctionDecl::hasOneParamOrDefaultArgs() const {
+  return getNumParams() == 1 ||
+         (getNumParams() > 1 &&
+          std::all_of(param_begin() + 1, param_end(),
+                      [](ParmVarDecl *P) { return P->hasDefaultArg(); }));
+}
+
 /// The combination of the extern and inline keywords under MSVC forces
 /// the function to be required.
 ///

diff  --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 96e63416073a..5412aa7ed5e0 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2549,11 +2549,11 @@ CXXConstructorDecl *CXXConstructorDecl::getTargetConstructor() const {
 }
 
 bool CXXConstructorDecl::isDefaultConstructor() const {
-  // C++ [class.ctor]p5:
-  //   A default constructor for a class X is a constructor of class
-  //   X that can be called without an argument.
-  return (getNumParams() == 0) ||
-         (getNumParams() > 0 && getParamDecl(0)->hasDefaultArg());
+  // C++ [class.default.ctor]p1:
+  //   A default constructor for a class X is a constructor of class X for
+  //   which each parameter that is not a function parameter pack has a default
+  //   argument (including the case of a constructor with no parameters)
+  return getMinRequiredArguments() == 0;
 }
 
 bool
@@ -2564,7 +2564,7 @@ CXXConstructorDecl::isCopyConstructor(unsigned &TypeQuals) const {
 
 bool CXXConstructorDecl::isMoveConstructor(unsigned &TypeQuals) const {
   return isCopyOrMoveConstructor(TypeQuals) &&
-    getParamDecl(0)->getType()->isRValueReferenceType();
+         getParamDecl(0)->getType()->isRValueReferenceType();
 }
 
 /// Determine whether this is a copy or move constructor.
@@ -2579,10 +2579,8 @@ bool CXXConstructorDecl::isCopyOrMoveConstructor(unsigned &TypeQuals) const {
   //   first parameter is of type X&&, const X&&, volatile X&&, or
   //   const volatile X&&, and either there are no other parameters or else
   //   all other parameters have default arguments.
-  if ((getNumParams() < 1) ||
-      (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
-      (getPrimaryTemplate() != nullptr) ||
-      (getDescribedFunctionTemplate() != nullptr))
+  if (!hasOneParamOrDefaultArgs() || getPrimaryTemplate() != nullptr ||
+      getDescribedFunctionTemplate() != nullptr)
     return false;
 
   const ParmVarDecl *Param = getParamDecl(0);
@@ -2619,18 +2617,16 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const {
   if (isExplicit() && !AllowExplicit)
     return false;
 
-  return (getNumParams() == 0 &&
-          getType()->castAs<FunctionProtoType>()->isVariadic()) ||
-         (getNumParams() == 1) ||
-         (getNumParams() > 1 &&
-          (getParamDecl(1)->hasDefaultArg() ||
-           getParamDecl(1)->isParameterPack()));
+  // FIXME: This has nothing to do with the definition of converting
+  // constructor, but is convenient for how we use this function in overload
+  // resolution.
+  return getNumParams() == 0
+             ? getType()->castAs<FunctionProtoType>()->isVariadic()
+             : getMinRequiredArguments() <= 1;
 }
 
 bool CXXConstructorDecl::isSpecializationCopyingObject() const {
-  if ((getNumParams() < 1) ||
-      (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
-      (getDescribedFunctionTemplate() != nullptr))
+  if (!hasOneParamOrDefaultArgs() || getDescribedFunctionTemplate() != nullptr)
     return false;
 
   const ParmVarDecl *Param = getParamDecl(0);

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index cedd9437e001..a137e6c0b745 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -38,8 +38,9 @@
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Template.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
 #include <map>
 #include <set>
@@ -304,18 +305,22 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc,
   ParmVarDecl *Param = cast<ParmVarDecl>(param);
   UnparsedDefaultArgLocs.erase(Param);
 
+  auto Fail = [&] {
+    Param->setInvalidDecl();
+    Param->setDefaultArg(new (Context) OpaqueValueExpr(
+        EqualLoc, Param->getType().getNonReferenceType(), VK_RValue));
+  };
+
   // Default arguments are only permitted in C++
   if (!getLangOpts().CPlusPlus) {
     Diag(EqualLoc, diag::err_param_default_argument)
       << DefaultArg->getSourceRange();
-    Param->setInvalidDecl();
-    return;
+    return Fail();
   }
 
   // Check for unexpanded parameter packs.
   if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument)) {
-    Param->setInvalidDecl();
-    return;
+    return Fail();
   }
 
   // C++11 [dcl.fct.default]p3
@@ -324,17 +329,18 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc,
   if (Param->isParameterPack()) {
     Diag(EqualLoc, diag::err_param_default_argument_on_parameter_pack)
         << DefaultArg->getSourceRange();
+    // Recover by discarding the default argument.
+    Param->setDefaultArg(nullptr);
     return;
   }
 
   // Check that the default argument is well-formed
   CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg, this);
-  if (DefaultArgChecker.Visit(DefaultArg)) {
-    Param->setInvalidDecl();
-    return;
-  }
+  if (DefaultArgChecker.Visit(DefaultArg))
+    return Fail();
 
-  SetParamDefaultArgument(Param, DefaultArg, EqualLoc);
+  if (SetParamDefaultArgument(Param, DefaultArg, EqualLoc))
+    return Fail();
 }
 
 /// ActOnParamUnparsedDefaultArgument - We've seen a default
@@ -419,14 +425,9 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
 }
 
 static bool functionDeclHasDefaultArgument(const FunctionDecl *FD) {
-  for (unsigned NumParams = FD->getNumParams(); NumParams > 0; --NumParams) {
-    const ParmVarDecl *PVD = FD->getParamDecl(NumParams-1);
-    if (!PVD->hasDefaultArg())
-      return false;
-    if (!PVD->hasInheritedDefaultArg())
-      return true;
-  }
-  return false;
+  return std::any_of(FD->param_begin(), FD->param_end(), [](ParmVarDecl *P) {
+    return P->hasDefaultArg() && !P->hasInheritedDefaultArg();
+  });
 }
 
 /// MergeCXXFunctionDecl - Merge two declarations of the same C++
@@ -1528,25 +1529,34 @@ void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) {
 /// [dcl.fct.default].
 void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
   unsigned NumParams = FD->getNumParams();
-  unsigned p;
+  unsigned ParamIdx = 0;
+
+  // This checking doesn't make sense for explicit specializations; their
+  // default arguments are determined by the declaration we're specializing,
+  // not by FD.
+  if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+    return;
+  if (auto *FTD = FD->getDescribedFunctionTemplate())
+    if (FTD->isMemberSpecialization())
+      return;
 
   // Find first parameter with a default argument
-  for (p = 0; p < NumParams; ++p) {
-    ParmVarDecl *Param = FD->getParamDecl(p);
+  for (; ParamIdx < NumParams; ++ParamIdx) {
+    ParmVarDecl *Param = FD->getParamDecl(ParamIdx);
     if (Param->hasDefaultArg())
       break;
   }
 
-  // C++11 [dcl.fct.default]p4:
+  // C++20 [dcl.fct.default]p4:
   //   In a given function declaration, each parameter subsequent to a parameter
   //   with a default argument shall have a default argument supplied in this or
-  //   a previous declaration or shall be a function parameter pack. A default
-  //   argument shall not be redefined by a later declaration (not even to the
-  //   same value).
-  unsigned LastMissingDefaultArg = 0;
-  for (; p < NumParams; ++p) {
-    ParmVarDecl *Param = FD->getParamDecl(p);
-    if (!Param->hasDefaultArg() && !Param->isParameterPack()) {
+  //   a previous declaration, unless the parameter was expanded from a
+  //   parameter pack, or shall be a function parameter pack.
+  for (; ParamIdx < NumParams; ++ParamIdx) {
+    ParmVarDecl *Param = FD->getParamDecl(ParamIdx);
+    if (!Param->hasDefaultArg() && !Param->isParameterPack() &&
+        !(CurrentInstantiationScope &&
+          CurrentInstantiationScope->isLocalPackExpansion(Param))) {
       if (Param->isInvalidDecl())
         /* We already complained about this parameter. */;
       else if (Param->getIdentifier())
@@ -1556,21 +1566,6 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
       else
         Diag(Param->getLocation(),
              diag::err_param_default_argument_missing);
-
-      LastMissingDefaultArg = p;
-    }
-  }
-
-  if (LastMissingDefaultArg > 0) {
-    // Some default arguments were missing. Clear out all of the
-    // default arguments up to (and including) the last missing
-    // default argument, so that we leave the function parameters
-    // in a semantically valid state.
-    for (p = 0; p <= LastMissingDefaultArg; ++p) {
-      ParmVarDecl *Param = FD->getParamDecl(p);
-      if (Param->hasDefaultArg()) {
-        Param->setDefaultArg(nullptr);
-      }
     }
   }
 }
@@ -9973,11 +9968,6 @@ void Sema::ActOnDelayedCXXMethodParameter(Scope *S, Decl *ParamD) {
 
   ParmVarDecl *Param = cast<ParmVarDecl>(ParamD);
 
-  // If this parameter has an unparsed default argument, clear it out
-  // to make way for the parsed default argument.
-  if (Param->hasUnparsedDefaultArg())
-    Param->setDefaultArg(nullptr);
-
   S->AddDecl(Param);
   if (Param->getDeclName())
     IdResolver.AddDecl(Param);
@@ -10111,11 +10101,9 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
   //   either there are no other parameters or else all other
   //   parameters have default arguments.
   if (!Constructor->isInvalidDecl() &&
-      ((Constructor->getNumParams() == 1) ||
-       (Constructor->getNumParams() > 1 &&
-        Constructor->getParamDecl(1)->hasDefaultArg())) &&
-      Constructor->getTemplateSpecializationKind()
-                                              != TSK_ImplicitInstantiation) {
+      Constructor->hasOneParamOrDefaultArgs() &&
+      Constructor->getTemplateSpecializationKind() !=
+          TSK_ImplicitInstantiation) {
     QualType ParamType = Constructor->getParamDecl(0)->getType();
     QualType ClassTy = Context.getTagDeclType(ClassDecl);
     if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
@@ -11175,8 +11163,7 @@ bool Sema::isInitListConstructor(const FunctionDecl *Ctor) {
   //   is of type std::initializer_list<E> or reference to possibly cv-qualified
   //   std::initializer_list<E> for some type E, and either there are no other
   //   parameters or else all other parameters have default arguments.
-  if (Ctor->getNumParams() < 1 ||
-      (Ctor->getNumParams() > 1 && !Ctor->getParamDecl(1)->hasDefaultArg()))
+  if (!Ctor->hasOneParamOrDefaultArgs())
     return false;
 
   QualType ArgType = Ctor->getParamDecl(0)->getType();

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 5e8b1d8a37cc..3c07b7d35b87 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -5502,6 +5502,15 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
 bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
                                   ParmVarDecl *Param) {
   if (Param->hasUnparsedDefaultArg()) {
+    // If we've already cleared out the location for the default argument,
+    // that means we're parsing it right now.
+    if (!UnparsedDefaultArgLocs.count(Param)) {
+      Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD;
+      Diag(CallLoc, diag::note_recursive_default_argument_used_here);
+      Param->setInvalidDecl();
+      return true;
+    }
+
     Diag(CallLoc,
          diag::err_use_of_default_argument_to_function_declared_later) <<
       FD << cast<CXXRecordDecl>(FD->getDeclContext())->getDeclName();
@@ -5588,13 +5597,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;
-  }
+  assert(Param->hasInit() && "default argument but no initializer?");
 
   // If the default expression creates temporaries, we need to
   // push them to the current stack of expression temporaries so they'll
@@ -5627,6 +5630,7 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
 
 ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
                                         FunctionDecl *FD, ParmVarDecl *Param) {
+  assert(Param->hasDefaultArg() && "can't build nonexistent default arg");
   if (CheckCXXDefaultArgExpr(CallLoc, FD, Param))
     return ExprError();
   return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext);

diff  --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 1aef43614d99..9739e1511039 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -6511,6 +6511,8 @@ static bool convertArgsForAvailabilityChecks(
   if (!Function->isVariadic() && Args.size() < Function->getNumParams()) {
     for (unsigned i = Args.size(), e = Function->getNumParams(); i != e; ++i) {
       ParmVarDecl *P = Function->getParamDecl(i);
+      if (!P->hasDefaultArg())
+        return false;
       ExprResult R = S.BuildCXXDefaultArgExpr(CallLoc, Function, P);
       if (R.isInvalid())
         return false;

diff  --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 4b6b92ccab2c..0cb50b3ea368 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -3609,6 +3609,13 @@ void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) {
   ArgumentPacks.push_back(Pack);
 }
 
+bool LocalInstantiationScope::isLocalPackExpansion(const Decl *D) {
+  for (DeclArgumentPack *Pack : ArgumentPacks)
+    if (std::find(Pack->begin(), Pack->end(), D) != Pack->end())
+      return true;
+  return false;
+}
+
 void LocalInstantiationScope::SetPartiallySubstitutedPack(NamedDecl *Pack,
                                           const TemplateArgument *ExplicitArgs,
                                                     unsigned NumExplicitArgs) {

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
old mode 100755
new mode 100644

diff  --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
index e3190245d240..9a435fc5b5ef 100644
--- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
@@ -42,8 +42,8 @@ struct X4 {
 
 // Check for "dangerous" default arguments that could cause recursion.
 struct X5 {
-  X5(); // expected-note {{requires 0 arguments}}
-  X5(const X5&, const X5& = X5()); // expected-warning{{no viable constructor copying parameter of type 'X5'}} expected-note {{requires 2 arguments}}
+  X5();
+  X5(const X5&, const X5& = X5()); // expected-error {{recursive evaluation of default argument}} expected-note {{used here}}
 };
 
 void g1(const X1&);
@@ -57,7 +57,7 @@ void test() {
   g2(X2()); // expected-warning{{C++98 requires an accessible copy constructor for class 'X2' when binding a reference to a temporary; was private}}
   g3(X3()); // expected-warning{{no viable constructor copying parameter of type 'X3'}}
   g4(X4<int>());
-  g5(X5());  // Generates a warning in the default argument.
+  g5(X5());
 }
 
 // Check that unavailable copy constructors still cause SFINAE failures.

diff  --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp
index 27eb6d1c078f..9095a7c43465 100644
--- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx0x-no-extra-copy.cpp
@@ -37,16 +37,23 @@ struct X4 {
   X4(const X4&, T = get_value_badly<T>());
 };
 
+struct X5 {
+  X5();
+  X5(const X5&, const X5& = X5());
+};
+
 void g1(const X1&);
 void g2(const X2&);
 void g3(const X3&);
 void g4(const X4<int>&);
+void g5(const X5&);
 
 void test() {
   g1(X1());
   g2(X2());
   g3(X3());
   g4(X4<int>());
+  g5(X5());
 }
 
 // Check that unavailable copy constructors do not cause SFINAE failures.

diff  --git a/clang/test/CXX/drs/dr0xx.cpp b/clang/test/CXX/drs/dr0xx.cpp
index 53bd6f3f0538..d998114442be 100644
--- a/clang/test/CXX/drs/dr0xx.cpp
+++ b/clang/test/CXX/drs/dr0xx.cpp
@@ -316,15 +316,16 @@ namespace dr25 { // dr25: yes
 namespace dr26 { // dr26: yes
   struct A { A(A, const A & = A()); }; // expected-error {{must pass its first argument by reference}}
   struct B {
-    B(); // expected-note 0-1{{candidate}}
+    B();
+    // FIXME: In C++98, we diagnose this twice.
     B(const B &, B = B());
 #if __cplusplus <= 201402L
-    // expected-error at -2 {{no matching constructor}} expected-note at -2 {{candidate}} expected-note at -2 {{here}}
+    // expected-error at -2 1+{{recursive evaluation of default argument}} expected-note at -2 1+{{used here}}
 #endif
   };
   struct C {
     static C &f();
-    C(const C &, C = f()); // expected-error {{no matching constructor}} expected-note {{candidate}} expected-note {{here}}
+    C(const C &, C = f()); // expected-error {{recursive evaluation of default argument}} expected-note {{used here}}
   };
 }
 

diff  --git a/clang/test/CXX/drs/dr1xx.cpp b/clang/test/CXX/drs/dr1xx.cpp
index 1e78c03be8ab..afa26f771eec 100644
--- a/clang/test/CXX/drs/dr1xx.cpp
+++ b/clang/test/CXX/drs/dr1xx.cpp
@@ -398,7 +398,7 @@ namespace dr136 { // dr136: 3.4
   void q() {
     j(A(), A()); // ok, has default argument
   }
-  extern "C" void k(int, int, int, int); // expected-note {{previous declaration is here}}
+  extern "C" void k(int, int, int, int); // expected-note 2{{previous declaration is here}}
   namespace NSA {
   struct A {
     friend void dr136::k(int, int, int, int = 0); // expected-error {{friend declaration specifying a default argument must be the only declaration}}
@@ -406,7 +406,7 @@ namespace dr136 { // dr136: 3.4
   }
   namespace NSB {
   struct A {
-    friend void dr136::k(int, int, int = 0, int); // expected-error {{missing default argument on parameter}}
+    friend void dr136::k(int, int, int = 0, int); // expected-error {{missing default argument on parameter}} expected-error {{must be the only declaration}}
   };
   }
   struct B {

diff  --git a/clang/test/CXX/drs/dr22xx.cpp b/clang/test/CXX/drs/dr22xx.cpp
index 8896281e9ca4..91be4b53cb47 100644
--- a/clang/test/CXX/drs/dr22xx.cpp
+++ b/clang/test/CXX/drs/dr22xx.cpp
@@ -35,3 +35,91 @@ namespace dr2292 { // dr2292: 9
   }
 #endif
 }
+
+namespace dr2233 { // dr2233: 11
+#if __cplusplus >= 201103L
+template <typename... T>
+void f(int i = 0, T... args) {}
+
+template <typename... T>
+void g(int i = 0, T... args, T... args2) {}
+
+template <typename... T>
+void h(int i = 0, T... args, int j = 1) {}
+
+template <typename... T, typename... U>
+void i(int i = 0, T... args, int j = 1, U... args2) {}
+
+template <class... Ts>
+void j(int i = 0, Ts... ts) {}
+
+template <>
+void j<int>(int i, int j) {}
+
+template
+void j(int, int, int);
+
+extern template
+void j(int, int, int, int);
+
+// PR23029
+// Ensure instantiating the templates works.
+void use() {
+  f();
+  f(0, 1);
+  f<int>(1, 2);
+  g<int>(1, 2, 3);
+  h(0, 1);
+  i();
+  i(3);
+  i<int>(3, 2);
+  i<int>(3, 2, 1);
+  i<int, int>(1, 2, 3, 4, 5);
+  j();
+  j(1);
+  j(1, 2);
+  j<int>(1, 2);
+}
+
+namespace MultilevelSpecialization {
+  template<typename ...T> struct A {
+    template <T... V> void f(int i = 0, int (&... arr)[V]);
+  };
+  template<> template<>
+    void A<int, int>::f<1, 1>(int i, int (&arr1a)[1], int (&arr2a)[1]) {}
+
+  // FIXME: I believe this example is valid, at least up to the first explicit
+  // specialization, but Clang can't cope with explicit specializations that
+  // expand packs into a sequence of parameters. If we ever start accepting
+  // that, we'll need to decide whether it's OK for arr1a to be missing its
+  // default argument -- how far back do we look when determining whether a
+  // parameter was expanded from a pack?
+  //   -- zygoloid 2020-06-02
+  template<typename ...T> struct B {
+    template <T... V> void f(int i = 0, int (&... arr)[V]);
+  };
+  template<> template<int a, int b>
+    void B<int, int>::f(int i, int (&arr1)[a], int (&arr2)[b]) {} // expected-error {{does not match}}
+  template<> template<>
+    void B<int, int>::f<1, 1>(int i, int (&arr1a)[1], int (&arr2a)[1]) {}
+}
+
+namespace CheckAfterMerging1 {
+  template <typename... T> void f() {
+    void g(int, int = 0);
+    void g(int = 0, T...);
+    g();
+  }
+  void h() { f<int>(); }
+}
+
+namespace CheckAfterMerging2 {
+  template <typename... T> void f() {
+    void g(int = 0, T...);
+    void g(int, int = 0);
+    g();
+  }
+  void h() { f<int>(); }
+}
+#endif
+} // namespace dr2233

diff  --git a/clang/test/CXX/drs/dr7xx.cpp b/clang/test/CXX/drs/dr7xx.cpp
index 147560d3037b..dc1d7e86c58b 100644
--- a/clang/test/CXX/drs/dr7xx.cpp
+++ b/clang/test/CXX/drs/dr7xx.cpp
@@ -219,16 +219,4 @@ namespace dr727 { // dr727: partial
   Collision<int, int> c; // expected-note {{in instantiation of}}
 }
 
-namespace dr777 { // dr777: 3.7
-#if __cplusplus >= 201103L
-template <typename... T>
-void f(int i = 0, T ...args) {}
-void ff() { f(); }
-
-template <typename... T>
-void g(int i = 0, T ...args, T ...args2) {}
-
-template <typename... T>
-void h(int i = 0, T ...args, int j = 1) {}
-#endif
-}
+// dr777 superseded by dr2233

diff  --git a/clang/test/CXX/expr/expr.post/expr.call/p4.cpp b/clang/test/CXX/expr/expr.post/expr.call/p4.cpp
new file mode 100644
index 000000000000..837e823159ae
--- /dev/null
+++ b/clang/test/CXX/expr/expr.post/expr.call/p4.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -verify %s
+
+void a(int x = 0, int y); // #1 expected-error {{missing default argument on parameter 'y'}}
+void b() {
+  a(); // expected-error {{no matching function}} expected-note@#1 {{requires 2 arguments, but 0 were provided}}
+  a(0); // expected-error {{no matching function}} expected-note@#1 {{requires 2 arguments, but 1 was provided}}
+  a(0, 0);
+}
+
+void a(int x, int y = 0);
+void c() {
+  a();
+  a(0);
+  a(0, 0);
+}
+
+template<typename ...T> void f(int x = 0, T ...); // #2
+void g() {
+  f<int>(); // expected-error {{no matching function}} expected-note@#2 {{requires 2 arguments, but 0 were provided}}
+  f<int>(0); // expected-error {{no matching function}} expected-note@#2 {{requires 2 arguments, but 1 was provided}}
+  f<int>(0, 0);
+}

diff  --git a/clang/test/SemaCXX/abstract.cpp b/clang/test/SemaCXX/abstract.cpp
index ffd36be5b797..1fda21caea49 100644
--- a/clang/test/SemaCXX/abstract.cpp
+++ b/clang/test/SemaCXX/abstract.cpp
@@ -258,7 +258,8 @@ namespace test5 {
   struct A { A(int); virtual ~A() = 0; }; // expected-note {{pure virtual method}}
   const A &a = 0; // expected-error {{abstract class}}
   void f(const A &a = 0); // expected-error {{abstract class}}
-  void g() { f(0); } // expected-error {{abstract class}}
+  void g(const A &a);
+  void h() { g(0); } // expected-error {{abstract class}}
 }
 
 // PR9247: Crash on invalid in clang::Sema::ActOnFinishCXXMemberSpecification

diff  --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index a8ded62e88ee..084e9701464d 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -2046,9 +2046,9 @@ namespace BadDefaultInit {
   // FIXME: The "constexpr constructor must initialize all members" diagnostic
   // here is bogus (we discard the k(k) initializer because the parameter 'k'
   // has been marked invalid).
-  struct B { // expected-note 2{{candidate}}
-    constexpr B( // expected-warning {{initialize all members}} expected-note {{candidate}}
-        int k = X<B().k>::n) : // expected-error {{no matching constructor}}
+  struct B {
+    constexpr B( // expected-warning {{initialize all members}}
+        int k = X<B().k>::n) : // expected-error {{default argument to function 'B' that is declared later}} expected-note {{here}}
       k(k) {}
     int k; // expected-note {{not initialized}}
   };

diff  --git a/clang/test/SemaCXX/decl-init-ref.cpp b/clang/test/SemaCXX/decl-init-ref.cpp
index fb5ca8c1491f..f515630d3f5e 100644
--- a/clang/test/SemaCXX/decl-init-ref.cpp
+++ b/clang/test/SemaCXX/decl-init-ref.cpp
@@ -40,8 +40,8 @@ namespace PR16502 {
 namespace IncompleteTest {
   struct String;
   // expected-error at +1 {{reference to incomplete type 'const IncompleteTest::String' could not bind to an lvalue of type 'const char [1]'}}
-  void takeString(const String& = "") {} // expected-note {{passing argument to parameter here}} expected-note {{candidate function}}
+  void takeString(const String& = "") {} // expected-note {{passing argument to parameter here}}
   void test() {
-        takeString(); // expected-error {{no matching function for call}}
+        takeString();
   }
 }

diff  --git a/clang/test/SemaCXX/implicit-exception-spec.cpp b/clang/test/SemaCXX/implicit-exception-spec.cpp
index 8545e8422b2a..a15df0675a27 100644
--- a/clang/test/SemaCXX/implicit-exception-spec.cpp
+++ b/clang/test/SemaCXX/implicit-exception-spec.cpp
@@ -54,10 +54,12 @@ namespace ExceptionSpecification {
 }
 
 namespace DefaultArgument {
+  // FIXME: We should detect and diagnose the cyclic dependence of
+  // noexcept(Default()) on itself here.
   struct Default {
     struct T {
-      T(int = ExceptionIf<noexcept(Default())::f()); // expected-error {{call to implicitly-deleted default constructor}} expected-error {{expected '>'}} expected-note {{to match this '<'}}
-    } t; // expected-note {{has no default constructor}}
+      T(int = ExceptionIf<noexcept(Default())>::f());
+    } t;
   };
 }
 

diff  --git a/clang/test/SemaCXX/warn-bool-conversion.cpp b/clang/test/SemaCXX/warn-bool-conversion.cpp
index 6eca171f254e..7b671c52b5b9 100644
--- a/clang/test/SemaCXX/warn-bool-conversion.cpp
+++ b/clang/test/SemaCXX/warn-bool-conversion.cpp
@@ -11,13 +11,17 @@ int* j = false;
 #endif
 
 #if __cplusplus <= 199711L
-// expected-warning at +6 {{initialization of pointer of type 'int *' to null from a constant boolean expression}}
+// expected-warning at +5 {{initialization of pointer of type 'int *' to null from a constant boolean expression}}
 #else
-// expected-error at +4 {{cannot initialize a parameter of type 'int *' with an rvalue of type 'bool'}}
-// expected-note at +3 {{passing argument to parameter 'j' here}}
-// expected-note at +2 6 {{candidate function not viable: requires 2 arguments, but 1 was provided}}
+// expected-error at +3 {{cannot initialize a parameter of type 'int *' with an rvalue of type 'bool'}}
+// expected-note at +2 {{passing argument to parameter 'j' here}}
 #endif
-void foo(int* i, int *j=(false))
+void bar(int *j = false);
+
+#if __cplusplus > 199711L
+// expected-note at +2 4{{candidate function not viable: no known conversion}}
+#endif
+void foo(int *i)
 {
   foo(false);
 #if __cplusplus <= 199711L
@@ -26,19 +30,8 @@ void foo(int* i, int *j=(false))
 // expected-error at -4 {{no matching function for call to 'foo'}}
 #endif
 
-  foo((int*)false);
-#if __cplusplus <= 199711L
-// no-warning: explicit cast
-#else
-// expected-error at -4 {{no matching function for call to 'foo'}}
-#endif
-
-  foo(0);
-#if __cplusplus <= 199711L
-// no-warning: not a bool, even though its convertible to bool
-#else
-// expected-error at -4 {{no matching function for call to 'foo'}}
-#endif
+  foo((int*)false); // OK: explicit cast
+  foo(0); // OK: not a bool, even though it's convertible to bool
 
   foo(false == true);
 #if __cplusplus <= 199711L

diff  --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index defdf677ae01..1a06a85d0912 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -4681,7 +4681,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td><a href="https://wg21.link/cwg777">777</a></td>
     <td>CD2</td>
     <td>Default arguments and parameter packs</td>
-    <td class="full" align="center">Clang 3.7</td>
+    <td class="full" align="center">Superseded by <a href="#2233">2233</a></td>
   </tr>
   <tr id="778">
     <td><a href="https://wg21.link/cwg778">778</a></td>
@@ -13213,7 +13213,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td><a href="https://wg21.link/cwg2233">2233</a></td>
     <td>DRWP</td>
     <td>Function parameter packs following default arguments</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="full" align="center">Clang 11</td>
   </tr>
   <tr id="2234">
     <td><a href="https://wg21.link/cwg2234">2234</a></td>


        


More information about the cfe-commits mailing list