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@-2 {{does not have linkage}} expected-note@-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> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits