Author: Richard Smith Date: 2021-01-18T21:05:01-08:00 New Revision: e3065ce238475ec202c707f4c58d90df171626ca
URL: https://github.com/llvm/llvm-project/commit/e3065ce238475ec202c707f4c58d90df171626ca DIFF: https://github.com/llvm/llvm-project/commit/e3065ce238475ec202c707f4c58d90df171626ca.diff LOG: DR2064: decltype(E) is only a dependent type if E is type-dependent, not if E is merely instantiation-dependent. Previously reverted in 34e72a146111dd986889a0f0ec8767b2ca6b2913; re-committed with a fix to an issue that caused name mangling to assert. Added: Modified: clang/include/clang/AST/DependenceFlags.h clang/lib/AST/ASTContext.cpp clang/lib/AST/ItaniumMangle.cpp clang/lib/AST/Type.cpp clang/test/CXX/drs/dr20xx.cpp clang/test/CodeGenCXX/mangle-subst.cpp clang/test/Sema/invalid-bitwidth-expr.mm clang/test/SemaCXX/invalid-template-base-specifier.cpp clang/test/SemaTemplate/dependent-expr.cpp clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp clang/www/cxx_dr_status.html Removed: ################################################################################ diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h index ca96b65574bd..8c47047a7526 100644 --- a/clang/include/clang/AST/DependenceFlags.h +++ b/clang/include/clang/AST/DependenceFlags.h @@ -255,6 +255,12 @@ inline TypeDependence toTypeDependence(TemplateNameDependence D) { inline TypeDependence toTypeDependence(TemplateArgumentDependence D) { return Dependence(D).type(); } +/// Compute the dependence of a type that depends on the type of an expression, +/// given the dependence of that expression and of its type. +inline TypeDependence typeToTypeDependence(ExprDependence ED, TypeDependence TD) { + return Dependence(ED & ~ExprDependence::Value).type() | + (TD & TypeDependence::VariablyModified); +} inline NestedNameSpecifierDependence toNestedNameSpecifierDependendence(TypeDependence D) { diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 44545f00b146..0190573fe36e 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -5383,10 +5383,10 @@ QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const { DecltypeType *dt; // C++11 [temp.type]p2: - // If an expression e involves a template parameter, decltype(e) denotes a - // unique dependent type. Two such decltype-specifiers refer to the same - // type only if their expressions are equivalent (14.5.6.1). - if (e->isInstantiationDependent()) { + // If an expression e is type-dependent, decltype(e) denotes a unique + // dependent type. Two such decltype-specifiers refer to the same type only + // if their expressions are equivalent (14.5.6.1). + if (e->isTypeDependent()) { llvm::FoldingSetNodeID ID; DependentDecltypeType::Profile(ID, *this, e); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 73c8f17a5d36..1f8c11f6de96 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2578,6 +2578,11 @@ void CXXNameMangler::mangleType(QualType T) { if (!TST->isTypeAlias()) break; + // Don't desugar instantiation-dependent decltype / typeof types. We need + // to mangle the expression as written. + if (isa<DecltypeType, TypeOfType>(T)) + break; + QualType Desugared = T.getSingleStepDesugaredType(Context.getASTContext()); if (Desugared == T) @@ -5568,12 +5573,11 @@ static bool hasMangledSubstitutionQualifiers(QualType T) { bool CXXNameMangler::mangleSubstitution(QualType T) { if (!hasMangledSubstitutionQualifiers(T)) { - if (const RecordType *RT = T->getAs<RecordType>()) + if (const RecordType *RT = dyn_cast<RecordType>(T)) return mangleSubstitution(RT->getDecl()); } uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); - return mangleSubstitution(TypePtr); } @@ -5732,7 +5736,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { void CXXNameMangler::addSubstitution(QualType T) { if (!hasMangledSubstitutionQualifiers(T)) { - if (const RecordType *RT = T->getAs<RecordType>()) { + if (const RecordType *RT = dyn_cast<RecordType>(T)) { addSubstitution(RT->getDecl()); return; } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 034e175f1352..5dec80be9ccb 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -125,8 +125,7 @@ ArrayType::ArrayType(TypeClass tc, QualType et, QualType can, // template<int ...N> int arr[] = {N...}; : Type(tc, can, et->getDependence() | - (sz ? toTypeDependence( - turnValueToTypeDependence(sz->getDependence())) + (sz ? toTypeDependence(sz->getDependence()) : TypeDependence::None) | (tc == VariableArray ? TypeDependence::VariablyModified : TypeDependence::None) | @@ -3396,9 +3395,8 @@ QualType MacroQualifiedType::getModifiedType() const { TypeOfExprType::TypeOfExprType(Expr *E, QualType can) : Type(TypeOfExpr, can, - toTypeDependence(E->getDependence()) | - (E->getType()->getDependence() & - TypeDependence::VariablyModified)), + typeToTypeDependence(E->getDependence(), + E->getType()->getDependence())), TOExpr(E) {} bool TypeOfExprType::isSugared() const { @@ -3418,18 +3416,12 @@ void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID, } DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can) - // C++11 [temp.type]p2: "If an expression e involves a template parameter, - // decltype(e) denotes a unique dependent type." Hence a decltype type is - // type-dependent even if its expression is only instantiation-dependent. : Type(Decltype, can, - toTypeDependence(E->getDependence()) | - (E->isInstantiationDependent() ? TypeDependence::Dependent - : TypeDependence::None) | - (E->getType()->getDependence() & - TypeDependence::VariablyModified)), + typeToTypeDependence(E->getDependence(), + E->getType()->getDependence())), E(E), UnderlyingType(underlyingType) {} -bool DecltypeType::isSugared() const { return !E->isInstantiationDependent(); } +bool DecltypeType::isSugared() const { return !E->isTypeDependent(); } QualType DecltypeType::desugar() const { if (isSugared()) diff --git a/clang/test/CXX/drs/dr20xx.cpp b/clang/test/CXX/drs/dr20xx.cpp index 56cc1161a00c..6e1c0505a5ec 100644 --- a/clang/test/CXX/drs/dr20xx.cpp +++ b/clang/test/CXX/drs/dr20xx.cpp @@ -49,6 +49,18 @@ namespace dr2026 { // dr2026: 11 } } +namespace dr2064 { // dr2064: 12 +#if __cplusplus >= 201103L + template<typename T> struct X { + template<typename U> struct Y {}; + }; + template<typename T> void f() { + X<decltype(sizeof(T))>::Y<int> y; // ok + return X<decltype(sizeof(T))>::f(); // expected-error {{no member named 'f' in 'dr2064::X<unsigned}} + } +#endif +} + namespace dr2082 { // dr2082: 11 void test1(int x, int = sizeof(x)); // ok #if __cplusplus >= 201103L diff --git a/clang/test/CodeGenCXX/mangle-subst.cpp b/clang/test/CodeGenCXX/mangle-subst.cpp index 20f33a72fff8..78b1408fc0cd 100644 --- a/clang/test/CodeGenCXX/mangle-subst.cpp +++ b/clang/test/CodeGenCXX/mangle-subst.cpp @@ -96,3 +96,14 @@ typename X<T>::template Y<T>::type f(typename X<T>::template Y<T>::type2) { retu // CHECK: @_ZN12ManglePrefix1fIiEENS_1XIT_E1YIS2_E4typeENS5_5type2E template int f<int>(int); } + +namespace InstantiationDependentDecltype { + struct a { a(char); }; + struct b { a c(); }; + // FIXME: This mangling is incorrect; the second decltype type should be a + // substitution for the first. + // CHECK: @_ZN30InstantiationDependentDecltype1fINS_1bEEEvDTcvNS_1aEcldtcvT__E1cEEDTcvS2_cldtcvS3__E1cEES3_S3_S2_S2_ + // FIXME: @_ZN30InstantiationDependentDecltype1fINS_1bEEEvDTcvNS_1aEcldtcvT__E1cEES4_S3_S3_S2_S2_ + template<typename d> void f(decltype(a(d().c())), decltype(a(d().c())), d, d, a, a); + void g(a a, b b) { f(a, a, b, b, a, a); } +} diff --git a/clang/test/Sema/invalid-bitwidth-expr.mm b/clang/test/Sema/invalid-bitwidth-expr.mm index 41ca9496de4f..8ce498feb4af 100644 --- a/clang/test/Sema/invalid-bitwidth-expr.mm +++ b/clang/test/Sema/invalid-bitwidth-expr.mm @@ -26,6 +26,7 @@ auto func() { auto func() { // error-bit should be propagated from TemplateArgument to NestNameSpecifier. class Base<decltype(Foo(T()))>::type C; // expected-error {{no matching function for call to 'Foo'}} + // expected-error@-1 {{no class named 'type' in 'Base<bool>'}} return C; } struct Z { diff --git a/clang/test/SemaCXX/invalid-template-base-specifier.cpp b/clang/test/SemaCXX/invalid-template-base-specifier.cpp index 7a1a7f801c45..77601402a85c 100644 --- a/clang/test/SemaCXX/invalid-template-base-specifier.cpp +++ b/clang/test/SemaCXX/invalid-template-base-specifier.cpp @@ -12,11 +12,11 @@ void test() { Crash<int>(); } // expected-note {{in instantiation of template cl template <typename T> using Alias = decltype(Foo(T())); // expected-error {{no matching function for call to 'Foo'}} template <typename T> -struct Crash2 : decltype(Alias<T>()) { // expected-note {{in instantiation of template type alias 'Alias' requested here}} +struct Crash2 : decltype(Alias<T>()) { // expected-note {{in instantiation of template type alias 'Alias' requested here}} expected-error {{base specifier must name a class}} Crash2(){}; }; -void test2() { Crash2<int>(); } // expected-note {{in instantiation of template class 'Crash2<int>' requested here}} +void test2() { Crash2<int>(); } // expected-note 2{{in instantiation of template class 'Crash2<int>' requested here}} template <typename T> class Base {}; diff --git a/clang/test/SemaTemplate/dependent-expr.cpp b/clang/test/SemaTemplate/dependent-expr.cpp index abdb8e9c4a9f..dace7e28788d 100644 --- a/clang/test/SemaTemplate/dependent-expr.cpp +++ b/clang/test/SemaTemplate/dependent-expr.cpp @@ -129,7 +129,12 @@ namespace PR45083 { template<typename> void f() { decltype(({})) x; // expected-error {{incomplete type}} } - template void f<int>(); // expected-note {{instantiation of}} + template void f<int>(); + + template<typename T> void f2() { + decltype(({T();})) x; // expected-error {{incomplete type}} + } + template void f2<void>(); // expected-note {{instantiation of}} template<typename> auto g() { auto c = [](auto, int) -> decltype(({})) {}; diff --git a/clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp index 03ef78f8cf14..b9a1c933560d 100644 --- a/clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp +++ b/clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp @@ -115,6 +115,12 @@ namespace Auto { int n; template<auto A, decltype(A) B = &n> struct SubstFailure; - TInt<SubstFailure> isf; // FIXME: this should be ill-formed + TInt<SubstFailure> isf; // expected-error {{template template argument has diff erent template parameters than its corresponding template template parameter}} TIntPtr<SubstFailure> ipsf; + + template<template<auto A, auto B, decltype(A)> typename C> struct TAutoAutoFirst {}; + template<auto A, auto B, decltype(A)> struct AutoAutoFirst; + template<auto A, auto B, decltype(B)> struct AutoAutoSecond; + TAutoAutoFirst<AutoAutoFirst> aaf; + TAutoAutoFirst<AutoAutoSecond> aas; // FIXME: this should be rejected due to parameter mismatch } diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index f2f711b55094..f85bc49bb3d0 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -12198,7 +12198,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td><a href="https://wg21.link/cwg2064">2064</a></td> <td>CD4</td> <td>Conflicting specifications for dependent <I>decltype-specifier</I>s</td> - <td class="none" align="center">Unknown</td> + <td class="unreleased" align="center">Clang 12</td> </tr> <tr class="open" id="2065"> <td><a href="https://wg21.link/cwg2065">2065</a></td> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits