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();
// 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
}
--- /dev/null
+// 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'}}
+}