[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