[llvm-branch-commits] [clang] 6b760a5 - DR2100: &expr is value-dependent if expr constant-evaluates to a
Richard Smith via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Dec 15 14:58:35 PST 2020
Author: Richard Smith
Date: 2020-12-15T14:53:26-08:00
New Revision: 6b760a50f52142e401a6380ff71f933cda22a909
URL: https://github.com/llvm/llvm-project/commit/6b760a50f52142e401a6380ff71f933cda22a909
DIFF: https://github.com/llvm/llvm-project/commit/6b760a50f52142e401a6380ff71f933cda22a909.diff
LOG: DR2100: &expr is value-dependent if expr constant-evaluates to a
dependent declaration.
Added:
Modified:
clang/include/clang/AST/ComputeDependence.h
clang/lib/AST/ComputeDependence.cpp
clang/lib/AST/Expr.cpp
clang/test/CXX/drs/dr21xx.cpp
clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
clang/www/cxx_dr_status.html
Removed:
################################################################################
diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h
index 6af0e4604b63..04e8e2c7d2cc 100644
--- a/clang/include/clang/AST/ComputeDependence.h
+++ b/clang/include/clang/AST/ComputeDependence.h
@@ -107,7 +107,7 @@ class ObjCMessageExpr;
ExprDependence computeDependence(FullExpr *E);
ExprDependence computeDependence(OpaqueValueExpr *E);
ExprDependence computeDependence(ParenExpr *E);
-ExprDependence computeDependence(UnaryOperator *E);
+ExprDependence computeDependence(UnaryOperator *E, const ASTContext &Ctx);
ExprDependence computeDependence(UnaryExprOrTypeTraitExpr *E);
ExprDependence computeDependence(ArraySubscriptExpr *E);
ExprDependence computeDependence(MatrixSubscriptExpr *E);
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index d837ae29cb54..79e3b3b099fc 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -37,9 +37,38 @@ ExprDependence clang::computeDependence(ParenExpr *E) {
return E->getSubExpr()->getDependence();
}
-ExprDependence clang::computeDependence(UnaryOperator *E) {
- return toExprDependence(E->getType()->getDependence()) |
- E->getSubExpr()->getDependence();
+ExprDependence clang::computeDependence(UnaryOperator *E,
+ const ASTContext &Ctx) {
+ ExprDependence Dep = toExprDependence(E->getType()->getDependence()) |
+ E->getSubExpr()->getDependence();
+
+ // C++ [temp.dep.constexpr]p5:
+ // An expression of the form & qualified-id where the qualified-id names a
+ // dependent member of the current instantiation is value-dependent. An
+ // expression of the form & cast-expression is also value-dependent if
+ // evaluating cast-expression as a core constant expression succeeds and
+ // the result of the evaluation refers to a templated entity that is an
+ // object with static or thread storage duration or a member function.
+ //
+ // What this amounts to is: constant-evaluate the operand and check whether it
+ // refers to a templated entity other than a variable with local storage.
+ if (Ctx.getLangOpts().CPlusPlus11 && E->getOpcode() == UO_AddrOf &&
+ !(Dep & ExprDependence::Value)) {
+ Expr::EvalResult Result;
+ SmallVector<PartialDiagnosticAt, 8> Diag;
+ Result.Diag = &Diag;
+ if (E->getSubExpr()->EvaluateAsConstantExpr(Result, Ctx) && Diag.empty() &&
+ Result.Val.isLValue()) {
+ auto *VD = Result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
+ if (VD && VD->isTemplated()) {
+ auto *VarD = dyn_cast<VarDecl>(VD);
+ if (!VarD || !VarD->hasLocalStorage())
+ Dep |= ExprDependence::Value;
+ }
+ }
+ }
+
+ return Dep;
}
ExprDependence clang::computeDependence(UnaryExprOrTypeTraitExpr *E) {
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 1bd032a04a51..50beeb5cabb1 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -4422,7 +4422,7 @@ UnaryOperator::UnaryOperator(const ASTContext &Ctx, Expr *input, Opcode opc,
UnaryOperatorBits.HasFPFeatures = FPFeatures.requiresTrailingStorage();
if (hasStoredFPFeatures())
setStoredFPFeatures(FPFeatures);
- setDependence(computeDependence(this));
+ setDependence(computeDependence(this, Ctx));
}
UnaryOperator *UnaryOperator::Create(const ASTContext &C, Expr *input,
diff --git a/clang/test/CXX/drs/dr21xx.cpp b/clang/test/CXX/drs/dr21xx.cpp
index 6810944cde65..98593e543e72 100644
--- a/clang/test/CXX/drs/dr21xx.cpp
+++ b/clang/test/CXX/drs/dr21xx.cpp
@@ -8,6 +8,31 @@
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
#endif
+namespace dr2100 { // dr2100: 12
+ template<const int *P, bool = true> struct X {};
+ template<typename T> struct A {
+ static const int n = 1;
+ int f() {
+ return X<&n>::n; // ok, value-dependent
+ }
+ int g() {
+ static const int n = 2;
+ return X<&n>::n; // ok, value-dependent
+#if __cplusplus < 201702L
+ // expected-error at -2 {{does not have linkage}} expected-note at -3 {{here}}
+#endif
+ }
+ };
+ template<const int *P> struct X<P> {
+#if __cplusplus < 201103L
+ static const int n = 0;
+#else
+ static const int n = *P;
+#endif
+ };
+ int q = A<int>().f() + A<int>().g();
+}
+
namespace dr2103 { // dr2103: yes
void f() {
int a;
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
index 0cfbfdcf4864..675f957ef6fa 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
@@ -468,3 +468,38 @@ namespace PR46637 {
X<f> y;
int n = y.call(); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void *'}}
}
+
+namespace PR48517 {
+ template<const int *P> struct A { static constexpr const int *p = P; };
+ template<typename T> auto make_nonconst() {
+ static int n;
+ return A<&n>();
+ };
+ using T = decltype(make_nonconst<int>()); // expected-note {{previous}}
+ using U = decltype(make_nonconst<float>());
+ static_assert(T::p != U::p);
+ using T = U; // expected-error {{
diff erent types}}
+
+ template<typename T> auto make_const() {
+ static constexpr int n = 42;
+ return A<&n>();
+ };
+ using V = decltype(make_const<int>()); // expected-note {{previous}}
+ using W = decltype(make_const<float>());
+ static_assert(*V::p == *W::p);
+ static_assert(V::p != W::p);
+ using V = W; // expected-error {{
diff erent types}}
+
+ template<auto V> struct Q {
+ using X = int;
+ static_assert(V == "primary template should not be instantiated");
+ };
+ template<typename T> struct R {
+ int n;
+ constexpr int f() {
+ return Q<&R::n>::X;
+ }
+ };
+ template<> struct Q<&R<int>::n> { static constexpr int X = 1; };
+ static_assert(R<int>().f() == 1);
+}
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index f7e4e98ccf4a..9f065c3ba6f5 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -12415,7 +12415,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://wg21.link/cwg2100">2100</a></td>
<td>C++17</td>
<td>Value-dependent address of static data member of class template</td>
- <td class="none" align="center">Unknown</td>
+ <td class="unreleased" align="center">Clang 12</td>
</tr>
<tr id="2101">
<td><a href="https://wg21.link/cwg2101">2101</a></td>
More information about the llvm-branch-commits
mailing list