[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