Skip to content

Commit 5951ff4

Browse files
committed
[clang] CWG 2082 and 2346: loosen the restrictions on parameters and local variables in default arguments.
This patch implements the resolution of CWG 2082 and CWG 2346. The resolution of CWG 2082 changed [dcl.fct.default]p7 and p9 to allow a parameter or local variable to appear in a default argument if not in a potentially-evaluated expression. The resolution of CWG 2346 changed [dcl.fct.default]p7 to allow a local variable to appear in a default argument if not odr-used. An issue remains after this patch (see the FIXME in test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp). This is addressed by the next patch. Differential Revision: https://reviews.llvm.org/D81615 Reviewed By: rsmith, erichkeane
1 parent 0418005 commit 5951ff4

File tree

6 files changed

+71
-17
lines changed

6 files changed

+71
-17
lines changed

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,22 +87,31 @@ bool CheckDefaultArgumentVisitor::VisitExpr(const Expr *Node) {
8787
bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) {
8888
const NamedDecl *Decl = DRE->getDecl();
8989
if (const auto *Param = dyn_cast<ParmVarDecl>(Decl)) {
90-
// C++ [dcl.fct.default]p9
91-
// Default arguments are evaluated each time the function is
92-
// called. The order of evaluation of function arguments is
93-
// unspecified. Consequently, parameters of a function shall not
94-
// be used in default argument expressions, even if they are not
95-
// evaluated. Parameters of a function declared before a default
96-
// argument expression are in scope and can hide namespace and
97-
// class member names.
98-
return S.Diag(DRE->getBeginLoc(),
99-
diag::err_param_default_argument_references_param)
100-
<< Param->getDeclName() << DefaultArg->getSourceRange();
90+
// C++ [dcl.fct.default]p9:
91+
// [...] parameters of a function shall not be used in default
92+
// argument expressions, even if they are not evaluated. [...]
93+
//
94+
// C++17 [dcl.fct.default]p9 (by CWG 2082):
95+
// [...] A parameter shall not appear as a potentially-evaluated
96+
// expression in a default argument. [...]
97+
//
98+
if (DRE->isNonOdrUse() != NOUR_Unevaluated)
99+
return S.Diag(DRE->getBeginLoc(),
100+
diag::err_param_default_argument_references_param)
101+
<< Param->getDeclName() << DefaultArg->getSourceRange();
101102
} else if (const auto *VDecl = dyn_cast<VarDecl>(Decl)) {
102-
// C++ [dcl.fct.default]p7
103+
// C++ [dcl.fct.default]p7:
103104
// Local variables shall not be used in default argument
104105
// expressions.
105-
if (VDecl->isLocalVarDecl())
106+
//
107+
// C++17 [dcl.fct.default]p7 (by CWG 2082):
108+
// A local variable shall not appear as a potentially-evaluated
109+
// expression in a default argument.
110+
//
111+
// C++20 [dcl.fct.default]p7 (DR as part of P0588R1, see also CWG 2346):
112+
// Note: A local variable cannot be odr-used (6.3) in a default argument.
113+
//
114+
if (VDecl->isLocalVarDecl() && !DRE->isNonOdrUse())
106115
return S.Diag(DRE->getBeginLoc(),
107116
diag::err_param_default_argument_references_local)
108117
<< VDecl->getDeclName() << DefaultArg->getSourceRange();
Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s
22

3-
void h()
4-
{
5-
int i;
6-
extern void h2(int x = sizeof(i)); // expected-error {{default argument references local variable 'i' of enclosing function}}
3+
void h() {
4+
int i1 = 0;
5+
extern void h1(int x = i1);
6+
// expected-error@-1 {{default argument references local variable 'i1' of enclosing function}}
7+
8+
const int i2 = 0;
9+
extern void h2a(int x = i2); // FIXME: ok, not odr-use
10+
// expected-error@-1 {{default argument references local variable 'i2' of enclosing function}}
11+
extern void h2b(int x = i2 + 0); // ok, not odr-use
12+
13+
const int i3 = 0;
14+
extern void h3(const int *x = &i3);
15+
// expected-error@-1 {{default argument references local variable 'i3' of enclosing function}}
16+
17+
const int i4 = 0;
18+
extern void h4(int x = sizeof(i4)); // ok, not odr-use
19+
extern void h5(int x = decltype(i4 + 4)()); // ok, not odr-use
720
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s
22
class A {
33
void f(A* p = this) { } // expected-error{{invalid use of 'this'}}
4+
5+
void test();
46
};
7+
8+
void A::test() {
9+
void g(int = this); // expected-error {{default argument references 'this'}}
10+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
void h() {
4+
void f1(int x, int y = sizeof(x)); // ok
5+
void f2(int x, int y = decltype(x)()); // ok
6+
void f3(int x, int y = x);
7+
// expected-error@-1 {{default argument references parameter 'x'}}
8+
void f4(int x, int y = x + 0);
9+
// expected-error@-1 {{default argument references parameter 'x'}}
10+
void f5(int x, int y = ((void)x, 0));
11+
// expected-error@-1 {{default argument references parameter 'x'}}
12+
}

clang/test/CXX/drs/dr20xx.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ namespace dr2026 { // dr2026: 11
4949
}
5050
}
5151

52+
namespace dr2082 { // dr2082: 11
53+
void test1(int x, int = sizeof(x)); // ok
54+
#if __cplusplus >= 201103L
55+
void test2(int x, int = decltype(x){}); // ok
56+
#endif
57+
}
58+
5259
namespace dr2083 { // dr2083: partial
5360
#if __cplusplus >= 201103L
5461
void non_const_mem_ptr() {

clang/test/CXX/drs/dr23xx.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
55
// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
66

7+
namespace dr2346 { // dr2346: 11
8+
void test() {
9+
const int i2 = 0;
10+
extern void h2b(int x = i2 + 0); // ok, not odr-use
11+
}
12+
}
13+
714
namespace dr2352 { // dr2352: 10
815
int **p;
916
const int *const *const &f1() { return p; }

0 commit comments

Comments
 (0)