Skip to content

Commit

Permalink
[clang] CWG 2082 and 2346: loosen the restrictions on parameters and …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
riccibruno committed Jun 11, 2020
1 parent 0418005 commit 5951ff4
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 17 deletions.
35 changes: 22 additions & 13 deletions clang/lib/Sema/SemaDeclCXX.cpp
Expand Up @@ -87,22 +87,31 @@ bool CheckDefaultArgumentVisitor::VisitExpr(const Expr *Node) {
bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) {
const NamedDecl *Decl = DRE->getDecl();
if (const auto *Param = dyn_cast<ParmVarDecl>(Decl)) {
// C++ [dcl.fct.default]p9
// Default arguments are evaluated each time the function is
// called. The order of evaluation of function arguments is
// unspecified. Consequently, parameters of a function shall not
// be used in default argument expressions, even if they are not
// evaluated. Parameters of a function declared before a default
// argument expression are in scope and can hide namespace and
// class member names.
return S.Diag(DRE->getBeginLoc(),
diag::err_param_default_argument_references_param)
<< Param->getDeclName() << DefaultArg->getSourceRange();
// C++ [dcl.fct.default]p9:
// [...] parameters of a function shall not be used in default
// argument expressions, even if they are not evaluated. [...]
//
// C++17 [dcl.fct.default]p9 (by CWG 2082):
// [...] A parameter shall not appear as a potentially-evaluated
// expression in a default argument. [...]
//
if (DRE->isNonOdrUse() != NOUR_Unevaluated)
return S.Diag(DRE->getBeginLoc(),
diag::err_param_default_argument_references_param)
<< Param->getDeclName() << DefaultArg->getSourceRange();
} else if (const auto *VDecl = dyn_cast<VarDecl>(Decl)) {
// C++ [dcl.fct.default]p7
// C++ [dcl.fct.default]p7:
// Local variables shall not be used in default argument
// expressions.
if (VDecl->isLocalVarDecl())
//
// C++17 [dcl.fct.default]p7 (by CWG 2082):
// A local variable shall not appear as a potentially-evaluated
// expression in a default argument.
//
// C++20 [dcl.fct.default]p7 (DR as part of P0588R1, see also CWG 2346):
// Note: A local variable cannot be odr-used (6.3) in a default argument.
//
if (VDecl->isLocalVarDecl() && !DRE->isNonOdrUse())
return S.Diag(DRE->getBeginLoc(),
diag::err_param_default_argument_references_local)
<< VDecl->getDeclName() << DefaultArg->getSourceRange();
Expand Down
21 changes: 17 additions & 4 deletions clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp
@@ -1,7 +1,20 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s

void h()
{
int i;
extern void h2(int x = sizeof(i)); // expected-error {{default argument references local variable 'i' of enclosing function}}
void h() {
int i1 = 0;
extern void h1(int x = i1);
// expected-error@-1 {{default argument references local variable 'i1' of enclosing function}}

const int i2 = 0;
extern void h2a(int x = i2); // FIXME: ok, not odr-use
// expected-error@-1 {{default argument references local variable 'i2' of enclosing function}}
extern void h2b(int x = i2 + 0); // ok, not odr-use

const int i3 = 0;
extern void h3(const int *x = &i3);
// expected-error@-1 {{default argument references local variable 'i3' of enclosing function}}

const int i4 = 0;
extern void h4(int x = sizeof(i4)); // ok, not odr-use
extern void h5(int x = decltype(i4 + 4)()); // ok, not odr-use
}
6 changes: 6 additions & 0 deletions clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp
@@ -1,4 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
class A {
void f(A* p = this) { } // expected-error{{invalid use of 'this'}}

void test();
};

void A::test() {
void g(int = this); // expected-error {{default argument references 'this'}}
}
12 changes: 12 additions & 0 deletions clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p9.cpp
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s

void h() {
void f1(int x, int y = sizeof(x)); // ok
void f2(int x, int y = decltype(x)()); // ok
void f3(int x, int y = x);
// expected-error@-1 {{default argument references parameter 'x'}}
void f4(int x, int y = x + 0);
// expected-error@-1 {{default argument references parameter 'x'}}
void f5(int x, int y = ((void)x, 0));
// expected-error@-1 {{default argument references parameter 'x'}}
}
7 changes: 7 additions & 0 deletions clang/test/CXX/drs/dr20xx.cpp
Expand Up @@ -49,6 +49,13 @@ namespace dr2026 { // dr2026: 11
}
}

namespace dr2082 { // dr2082: 11
void test1(int x, int = sizeof(x)); // ok
#if __cplusplus >= 201103L
void test2(int x, int = decltype(x){}); // ok
#endif
}

namespace dr2083 { // dr2083: partial
#if __cplusplus >= 201103L
void non_const_mem_ptr() {
Expand Down
7 changes: 7 additions & 0 deletions clang/test/CXX/drs/dr23xx.cpp
Expand Up @@ -4,6 +4,13 @@
// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s

namespace dr2346 { // dr2346: 11
void test() {
const int i2 = 0;
extern void h2b(int x = i2 + 0); // ok, not odr-use
}
}

namespace dr2352 { // dr2352: 10
int **p;
const int *const *const &f1() { return p; }
Expand Down

0 comments on commit 5951ff4

Please sign in to comment.