[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