From 6b760a50f52142e401a6380ff71f933cda22a909 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 15 Dec 2020 13:23:08 -0800 Subject: [PATCH] DR2100: &expr is value-dependent if expr constant-evaluates to a dependent declaration. --- clang/include/clang/AST/ComputeDependence.h | 2 +- clang/lib/AST/ComputeDependence.cpp | 35 ++++++++++++++++++++-- clang/lib/AST/Expr.cpp | 2 +- clang/test/CXX/drs/dr21xx.cpp | 25 ++++++++++++++++ clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp | 35 ++++++++++++++++++++++ clang/www/cxx_dr_status.html | 2 +- 6 files changed, 95 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h index 6af0e46..04e8e2c 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 d837ae2..79e3b3b 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 Diag; + Result.Diag = &Diag; + if (E->getSubExpr()->EvaluateAsConstantExpr(Result, Ctx) && Diag.empty() && + Result.Val.isLValue()) { + auto *VD = Result.Val.getLValueBase().dyn_cast(); + if (VD && VD->isTemplated()) { + auto *VarD = dyn_cast(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 1bd032a..50beeb5 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 6810944..98593e5 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 struct X {}; + template 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 struct X

{ +#if __cplusplus < 201103L + static const int n = 0; +#else + static const int n = *P; +#endif + }; + int q = A().f() + A().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 0cfbfdc..675f957 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 y; int n = y.call(); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void *'}} } + +namespace PR48517 { + template struct A { static constexpr const int *p = P; }; + template auto make_nonconst() { + static int n; + return A<&n>(); + }; + using T = decltype(make_nonconst()); // expected-note {{previous}} + using U = decltype(make_nonconst()); + static_assert(T::p != U::p); + using T = U; // expected-error {{different types}} + + template auto make_const() { + static constexpr int n = 42; + return A<&n>(); + }; + using V = decltype(make_const()); // expected-note {{previous}} + using W = decltype(make_const()); + static_assert(*V::p == *W::p); + static_assert(V::p != W::p); + using V = W; // expected-error {{different types}} + + template struct Q { + using X = int; + static_assert(V == "primary template should not be instantiated"); + }; + template struct R { + int n; + constexpr int f() { + return Q<&R::n>::X; + } + }; + template<> struct Q<&R::n> { static constexpr int X = 1; }; + static_assert(R().f() == 1); +} diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index f7e4e98..9f065c3 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -12415,7 +12415,7 @@ and POD class 2100 C++17 Value-dependent address of static data member of class template - Unknown + Clang 12 2101 -- 2.7.4