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:
Richard Smith 2020-06-02 10:42:36 -07:00
parent af86a10bad
commit b5f2c4e45b
22 changed files with 257 additions and 134 deletions

View File

@ -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

View File

@ -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

View File

@ -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.
///

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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) {

0
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp Executable file → Normal file
View File

View File

@ -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.

View File

@ -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.

View File

@ -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}}
};
}

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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}}
};

View File

@ -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();
}
}

View File

@ -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;
};
}

View File

@ -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

View File

@ -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>