[llvm-branch-commits] [clang] 7e7f38f - DR1413 and part of P1815R2: Minor improvements to Clang's determination
Richard Smith via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Dec 15 14:58:37 PST 2020
Author: Richard Smith
Date: 2020-12-15T14:53:26-08:00
New Revision: 7e7f38f853fbf96c6ab2a0e5f9d7747ef8a76ffe
URL: https://github.com/llvm/llvm-project/commit/7e7f38f853fbf96c6ab2a0e5f9d7747ef8a76ffe
DIFF: https://github.com/llvm/llvm-project/commit/7e7f38f853fbf96c6ab2a0e5f9d7747ef8a76ffe.diff
LOG: DR1413 and part of P1815R2: Minor improvements to Clang's determination
of type- and value-dependency.
A static data member initialized to a constant inside a class template
is no longer considered value-dependent, per DR1413. A const but not
constexpr variable of literal type (other than integer or enumeration)
is no longer considered value-dependent, per P1815R2.
Added:
Modified:
clang/include/clang/AST/Decl.h
clang/lib/AST/ComputeDependence.cpp
clang/test/CXX/drs/dr14xx.cpp
clang/test/CXX/drs/dr21xx.cpp
clang/test/CXX/drs/dr2xx.cpp
clang/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp
clang/test/SemaCXX/typedef-redecl.cpp
clang/test/SemaCXX/vector.cpp
clang/www/cxx_dr_status.html
Removed:
################################################################################
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 7f6f143aa866..ab24c8779df2 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1262,6 +1262,9 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
/// constant expression, according to the relevant language standard.
/// This only checks properties of the declaration, and does not check
/// whether the initializer is in fact a constant expression.
+ ///
+ /// This corresponds to C++20 [expr.const]p3's notion of a
+ /// "potentially-constant" variable.
bool mightBeUsableInConstantExpressions(const ASTContext &C) const;
/// Determine whether this variable's value can be used in a
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 79e3b3b099fc..4026fdc76fd6 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -52,11 +52,12 @@ ExprDependence clang::computeDependence(UnaryOperator *E,
//
// 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 &&
+ if (Ctx.getLangOpts().CPlusPlus && E->getOpcode() == UO_AddrOf &&
!(Dep & ExprDependence::Value)) {
Expr::EvalResult Result;
SmallVector<PartialDiagnosticAt, 8> Diag;
Result.Diag = &Diag;
+ // FIXME: This doesn't enforce the C++98 constant expression rules.
if (E->getSubExpr()->EvaluateAsConstantExpr(Result, Ctx) && Diag.empty() &&
Result.Val.isLValue()) {
auto *VD = Result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
@@ -452,22 +453,21 @@ ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) {
Deps |= ExprDependence::UnexpandedPack;
Deps |= toExprDependence(Type->getDependence()) & ExprDependence::Error;
- // (TD) C++ [temp.dep.expr]p3:
+ // C++ [temp.dep.expr]p3:
// An id-expression is type-dependent if it contains:
- //
- // and
- //
- // (VD) C++ [temp.dep.constexpr]p2:
- // An identifier is value-dependent if it is:
- // (TD) - an identifier that was declared with dependent type
- // (VD) - a name declared with a dependent type,
+ // - an identifier associated by name lookup with one or more declarations
+ // declared with a dependent type
+ //
+ // [The "or more" case is not modeled as a DeclRefExpr. There are a bunch
+ // more bullets here that we handle by treating the declaration as having a
+ // dependent type if they involve a placeholder type that can't be deduced.]
if (Type->isDependentType())
return Deps | ExprDependence::TypeValueInstantiation;
else if (Type->isInstantiationDependentType())
Deps |= ExprDependence::Instantiation;
- // (TD) - a conversion-function-id that specifies a dependent type
+ // - a conversion-function-id that specifies a dependent type
if (Decl->getDeclName().getNameKind() ==
DeclarationName::CXXConversionFunctionName) {
QualType T = Decl->getDeclName().getCXXNameType();
@@ -478,23 +478,28 @@ ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) {
Deps |= ExprDependence::Instantiation;
}
- // (VD) - the name of a non-type template parameter,
+ // - a template-id that is dependent,
+ // - a nested-name-specifier or a qualified-id that names a member of an
+ // unknown specialization
+ // [These are not modeled as DeclRefExprs.]
+
+ // or if it names a dependent member of the current instantiation that is a
+ // static data member of type "array of unknown bound of T" for some T
+ // [handled below].
+
+ // C++ [temp.dep.constexpr]p2:
+ // An id-expression is value-dependent if:
+
+ // - it is type-dependent [handled above]
+
+ // - it is the name of a non-type template parameter,
if (isa<NonTypeTemplateParmDecl>(Decl))
return Deps | ExprDependence::ValueInstantiation;
- // (VD) - a constant with integral or enumeration type and is
- // initialized with an expression that is value-dependent.
- // (VD) - a constant with literal type and is initialized with an
- // expression that is value-dependent [C++11].
- // (VD) - FIXME: Missing from the standard:
- // - an entity with reference type and is initialized with an
- // expression that is value-dependent [C++11]
- if (VarDecl *Var = dyn_cast<VarDecl>(Decl)) {
- if ((Ctx.getLangOpts().CPlusPlus11
- ? Var->getType()->isLiteralType(Ctx)
- : Var->getType()->isIntegralOrEnumerationType()) &&
- (Var->getType().isConstQualified() ||
- Var->getType()->isReferenceType())) {
+ // - it names a potentially-constant variable that is initialized with an
+ // expression that is value-dependent
+ if (const auto *Var = dyn_cast<VarDecl>(Decl)) {
+ if (Var->mightBeUsableInConstantExpressions(Ctx)) {
if (const Expr *Init = Var->getAnyInitializer()) {
if (Init->isValueDependent())
Deps |= ExprDependence::ValueInstantiation;
@@ -503,25 +508,35 @@ ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) {
}
}
- // (VD) - FIXME: Missing from the standard:
- // - a member function or a static data member of the current
- // instantiation
+ // - it names a static data member that is a dependent member of the
+ // current instantiation and is not initialized in a member-declarator,
if (Var->isStaticDataMember() &&
- Var->getDeclContext()->isDependentContext()) {
- Deps |= ExprDependence::ValueInstantiation;
- TypeSourceInfo *TInfo = Var->getFirstDecl()->getTypeSourceInfo();
- if (TInfo->getType()->isIncompleteArrayType())
- Deps |= ExprDependence::Type;
+ Var->getDeclContext()->isDependentContext() &&
+ !Var->getFirstDecl()->hasInit()) {
+ const VarDecl *First = Var->getFirstDecl();
+ TypeSourceInfo *TInfo = First->getTypeSourceInfo();
+ if (TInfo->getType()->isIncompleteArrayType()) {
+ Deps |= ExprDependence::TypeValueInstantiation;
+ } else if (!First->hasInit()) {
+ Deps |= ExprDependence::ValueInstantiation;
+ }
}
return Deps;
}
- // (VD) - FIXME: Missing from the standard:
- // - a member function or a static data member of the current
- // instantiation
- if (isa<CXXMethodDecl>(Decl) && Decl->getDeclContext()->isDependentContext())
- Deps |= ExprDependence::ValueInstantiation;
+ // - it names a static member function that is a dependent member of the
+ // current instantiation
+ //
+ // FIXME: It's unclear that the restriction to static members here has any
+ // effect: any use of a non-static member function name requires either
+ // forming a pointer-to-member or providing an object parameter, either of
+ // which makes the overall expression value-dependent.
+ if (auto *MD = dyn_cast<CXXMethodDecl>(Decl)) {
+ if (MD->isStatic() && Decl->getDeclContext()->isDependentContext())
+ Deps |= ExprDependence::ValueInstantiation;
+ }
+
return Deps;
}
diff --git a/clang/test/CXX/drs/dr14xx.cpp b/clang/test/CXX/drs/dr14xx.cpp
index c68e6faa76c0..866f2fe0bf85 100644
--- a/clang/test/CXX/drs/dr14xx.cpp
+++ b/clang/test/CXX/drs/dr14xx.cpp
@@ -4,6 +4,29 @@
// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+namespace dr1413 { // dr1413: 12
+ template<int> struct Check {
+ typedef int type;
+ };
+ template<typename T> struct A : T {
+ static const int a = 1;
+ static const int b;
+ static void c();
+ void d();
+
+ void f() {
+ Check<true ? 0 : A::unknown_spec>::type *var1; // expected-error {{undeclared identifier 'var1'}}
+ Check<true ? 0 : a>::type *var2; // ok, variable declaration expected-note 0+{{here}}
+ Check<true ? 0 : b>::type *var3; // expected-error {{undeclared identifier 'var3'}}
+ Check<true ? 0 : (c, 0)>::type *var4; // expected-error {{undeclared identifier 'var4'}}
+ // value-dependent because of the implied type-dependent 'this->', not because of 'd'
+ Check<true ? 0 : (d(), 0)>::type *var5; // expected-error {{undeclared identifier 'var5'}}
+ // value-dependent because of the value-dependent '&' operator, not because of 'A::d'
+ Check<true ? 0 : (&A::d(), 0)>::type *var5; // expected-error {{undeclared identifier 'var5'}}
+ }
+ };
+}
+
namespace dr1423 { // dr1423: 11
#if __cplusplus >= 201103L
bool b1 = nullptr; // expected-error {{cannot initialize}}
diff --git a/clang/test/CXX/drs/dr21xx.cpp b/clang/test/CXX/drs/dr21xx.cpp
index 98593e543e72..62c56703195b 100644
--- a/clang/test/CXX/drs/dr21xx.cpp
+++ b/clang/test/CXX/drs/dr21xx.cpp
@@ -31,6 +31,23 @@ namespace dr2100 { // dr2100: 12
#endif
};
int q = A<int>().f() + A<int>().g();
+
+ // Corresponding constructs where the address is not taken are not
+ // value-dependent.
+ template<int N, bool = true> struct Y {};
+ template<typename T> struct B {
+ static const int n = 1;
+ int f() {
+ return Y<n>::declared_later; // expected-error {{no member named 'declared_later'}}
+ }
+ int g() {
+ static const int n = 2;
+ return Y<n>::declared_later; // expected-error {{no member named 'declared_later'}}
+ }
+ };
+ template<int N> struct Y<N> {
+ static const int declared_later = 0;
+ };
}
namespace dr2103 { // dr2103: yes
diff --git a/clang/test/CXX/drs/dr2xx.cpp b/clang/test/CXX/drs/dr2xx.cpp
index c02b7a8f3634..ab70b8742d00 100644
--- a/clang/test/CXX/drs/dr2xx.cpp
+++ b/clang/test/CXX/drs/dr2xx.cpp
@@ -292,9 +292,9 @@ namespace dr224 { // dr224: no
template <int, typename T> struct X { typedef T type; };
template <class T> class A {
static const int i = 5;
- X<i, int>::type w; // FIXME: expected-error {{missing 'typename'}}
- X<A::i, char>::type x; // FIXME: expected-error {{missing 'typename'}}
- X<A<T>::i, double>::type y; // FIXME: expected-error {{missing 'typename'}}
+ X<i, int>::type w;
+ X<A::i, char>::type x;
+ X<A<T>::i, double>::type y;
X<A<T*>::i, long>::type z; // expected-error {{missing 'typename'}}
int f();
};
diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp
index 8f2a599ab28a..11dd5194192b 100644
--- a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp
+++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp
@@ -1,7 +1,11 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
-// expected-no-diagnostics
-template<int n> struct S;
+template<int n> struct S; // expected-note 3{{here}}
+
+struct LiteralType {
+ constexpr LiteralType(int n) : n(n) {}
+ int n;
+};
template<int n> struct T {
T() {
@@ -11,18 +15,28 @@ template<int n> struct T {
S<s> check1; // ok, s is value-dependent
// - the name of a non-type template parameter
typename S<n>::T check2; // ok, n is value-dependent
- // - a constant with literal type and is initialized with an expression
- // that is value-dependent.
+ // - a potentially-constant variable that is initialized with an
+ // expression that is value-dependent.
const int k = n;
typename S<k>::T check3a; // ok, u is value-dependent
constexpr const int *p = &k;
typename S<*p>::T check3b; // ok, p is value-dependent
- // (missing from the standard)
- // - a reference and is initialized with an expression that is
- // value-dependent.
const int &i = k;
typename S<i>::T check4; // ok, i is value-dependent
+
+ static const int ki = 42;
+ const int &i2 = ki;
+ typename S<i2>::T check5; // expected-error {{undefined template}}
+
+ constexpr LiteralType x = n;
+ typename S<true ? 1 : x.n>::T check6; // ok, x is value-dependent
+
+ const LiteralType y = n;
+ typename S<true ? 2 : y.n>::T check7; // expected-error {{undefined template}}
+
+ constexpr LiteralType z = 42;
+ typename S<true ? 3 : z.n>::T check8; // expected-error {{undefined template}}
}
};
diff --git a/clang/test/SemaCXX/typedef-redecl.cpp b/clang/test/SemaCXX/typedef-redecl.cpp
index b53bcd2b4580..06883ffd4b5e 100644
--- a/clang/test/SemaCXX/typedef-redecl.cpp
+++ b/clang/test/SemaCXX/typedef-redecl.cpp
@@ -86,7 +86,7 @@ namespace PR11630 {
void f() {
S<int> a;
- a.f(); // expected-note{{in instantiation of member function 'PR11630::S<int>::f' requested here}}
+ a.f();
S2<1> b;
b.f();
S2<2> b2;
diff --git a/clang/test/SemaCXX/vector.cpp b/clang/test/SemaCXX/vector.cpp
index 724ccece0c42..4b2ebc99a183 100644
--- a/clang/test/SemaCXX/vector.cpp
+++ b/clang/test/SemaCXX/vector.cpp
@@ -426,6 +426,13 @@ struct ConstantValueNoDiag {
}
static constexpr double k = 1;
};
+template <typename T, int N>
+struct ConstantValueNoDiagDependentValue {
+ float4 f(float4 x) {
+ return k * x;
+ }
+ static constexpr double k = N;
+};
// The following two both diagnose because they cause a truncation. Test both
// the dependent type and non-dependent type versions.
@@ -437,6 +444,14 @@ struct DiagTrunc {
}
static constexpr double k = 1340282346638528859811704183484516925443.000000;
};
+template <typename T, int N>
+struct DiagTruncDependentValue {
+ float4 f(float4 x) {
+ // expected-error at +1{{as implicit conversion would cause truncation}}
+ return k * x;
+ }
+ static constexpr double k = N + 1340282346638528859811704183484516925443.000000;
+};
template <typename T>
struct DiagTruncDependentType {
float4 f(float4 x) {
@@ -467,9 +482,11 @@ void use() {
NormalMember<double>().f(theFloat4);
#if __cplusplus >= 201103L
ConstantValueNoDiag<double>().f(theFloat4);
- // expected-note at +1{{in instantiation of member function}}
+ ConstantValueNoDiagDependentValue<double, 1>().f(theFloat4);
DiagTrunc<double>().f(theFloat4);
// expected-note at +1{{in instantiation of member function}}
+ DiagTruncDependentValue<double, 0>().f(theFloat4);
+ // expected-note at +1{{in instantiation of member function}}
DiagTruncDependentType<double>().f(theFloat4);
PR45298Consumer<double>().f(theFloat4);
#endif // __cplusplus >= 201103L
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 9f065c3ba6f5..6e0206ab9e63 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -8293,7 +8293,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://wg21.link/cwg1413">1413</a></td>
<td>CD3</td>
<td>Missing cases of value-dependency</td>
- <td class="none" align="center">Unknown</td>
+ <td class="unreleased" align="center">Clang 12</td>
</tr>
<tr class="open" id="1414">
<td><a href="https://wg21.link/cwg1414">1414</a></td>
More information about the llvm-branch-commits
mailing list