[clang] 5951ff4 - [clang] CWG 2082 and 2346: loosen the restrictions on parameters and local variables in default arguments.
Bruno Ricci via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 11 04:45:16 PDT 2020
Author: Bruno Ricci
Date: 2020-06-11T12:41:08+01:00
New Revision: 5951ff4512332fff9d191da8661143a883d3b8aa
URL: https://github.com/llvm/llvm-project/commit/5951ff4512332fff9d191da8661143a883d3b8aa
DIFF: https://github.com/llvm/llvm-project/commit/5951ff4512332fff9d191da8661143a883d3b8aa.diff
LOG: [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
Added:
clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p9.cpp
Modified:
clang/lib/Sema/SemaDeclCXX.cpp
clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp
clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp
clang/test/CXX/drs/dr20xx.cpp
clang/test/CXX/drs/dr23xx.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e33df2527d2c..28a84d27c038 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -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();
diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp
index 164eb3682f31..07b527bbdc20 100644
--- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp
+++ b/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 at -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 at -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 at -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
}
diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp
index 1a08ab733287..ce2c9cb9fb9d 100644
--- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp
+++ b/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'}}
+}
diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p9.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p9.cpp
new file mode 100644
index 000000000000..0971b1458f57
--- /dev/null
+++ b/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 at -1 {{default argument references parameter 'x'}}
+ void f4(int x, int y = x + 0);
+ // expected-error at -1 {{default argument references parameter 'x'}}
+ void f5(int x, int y = ((void)x, 0));
+ // expected-error at -1 {{default argument references parameter 'x'}}
+}
diff --git a/clang/test/CXX/drs/dr20xx.cpp b/clang/test/CXX/drs/dr20xx.cpp
index c1429492a51a..56cc1161a00c 100644
--- a/clang/test/CXX/drs/dr20xx.cpp
+++ b/clang/test/CXX/drs/dr20xx.cpp
@@ -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() {
diff --git a/clang/test/CXX/drs/dr23xx.cpp b/clang/test/CXX/drs/dr23xx.cpp
index 85f592074607..3268838ac6c8 100644
--- a/clang/test/CXX/drs/dr23xx.cpp
+++ b/clang/test/CXX/drs/dr23xx.cpp
@@ -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; }
More information about the cfe-commits
mailing list