forked from OSchip/llvm-project
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.
This commit is contained in:
parent
af86a10bad
commit
b5f2c4e45b
|
@ -2439,6 +2439,14 @@ public:
|
|||
/// 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 different type from that of the function
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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@-2 {{no matching constructor}} expected-note@-2 {{candidate}} expected-note@-2 {{here}}
|
||||
// expected-error@-2 1+{{recursive evaluation of default argument}} expected-note@-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}}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
||||
};
|
||||
|
|
|
@ -40,8 +40,8 @@ namespace PR16502 {
|
|||
namespace IncompleteTest {
|
||||
struct String;
|
||||
// expected-error@+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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -11,13 +11,17 @@ int* j = false;
|
|||
#endif
|
||||
|
||||
#if __cplusplus <= 199711L
|
||||
// expected-warning@+6 {{initialization of pointer of type 'int *' to null from a constant boolean expression}}
|
||||
// expected-warning@+5 {{initialization of pointer of type 'int *' to null from a constant boolean expression}}
|
||||
#else
|
||||
// expected-error@+4 {{cannot initialize a parameter of type 'int *' with an rvalue of type 'bool'}}
|
||||
// expected-note@+3 {{passing argument to parameter 'j' here}}
|
||||
// expected-note@+2 6 {{candidate function not viable: requires 2 arguments, but 1 was provided}}
|
||||
// expected-error@+3 {{cannot initialize a parameter of type 'int *' with an rvalue of type 'bool'}}
|
||||
// expected-note@+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@+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@-4 {{no matching function for call to 'foo'}}
|
||||
#endif
|
||||
|
||||
foo((int*)false);
|
||||
#if __cplusplus <= 199711L
|
||||
// no-warning: explicit cast
|
||||
#else
|
||||
// expected-error@-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@-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
|
||||
|
|
|
@ -4681,7 +4681,7 @@ and <I>POD class</I></td>
|
|||
<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 @@ and <I>POD class</I></td>
|
|||
<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>
|
||||
|
|
Loading…
Reference in New Issue