diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -203,6 +203,7 @@ FunctionProtoTypes; mutable llvm::FoldingSet DependentTypeOfExprTypes; mutable llvm::FoldingSet DependentDecltypeTypes; + mutable llvm::FoldingSet DecltypeTypes; mutable llvm::FoldingSet TemplateTypeParmTypes; mutable llvm::FoldingSet ObjCTypeParamTypes; mutable llvm::FoldingSet diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -4468,14 +4468,16 @@ }; /// Represents the type `decltype(expr)` (C++11). -class DecltypeType : public Type { +class DecltypeType : public Type, public llvm::FoldingSetNode { Expr *E; QualType UnderlyingType; protected: friend class ASTContext; // ASTContext creates these. - DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType()); + const ASTContext &Context; + DecltypeType(Expr *E, QualType underlyingType, const ASTContext &Context, + QualType can = QualType()); public: Expr *getUnderlyingExpr() const { return E; } @@ -4488,6 +4490,10 @@ bool isSugared() const; static bool classof(const Type *T) { return T->getTypeClass() == Decltype; } + + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, E); } + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + Expr *E); }; /// Internal representation of canonical, dependent @@ -4496,18 +4502,9 @@ /// This class is used internally by the ASTContext to manage /// canonical, dependent types, only. Clients will only see instances /// of this class via DecltypeType nodes. -class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { - const ASTContext &Context; - +class DependentDecltypeType : public DecltypeType { public: DependentDecltypeType(const ASTContext &Context, Expr *E); - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, Context, getUnderlyingExpr()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - Expr *E); }; /// A unary type transform, which is a type constructed from another. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -5343,14 +5343,16 @@ /// nodes. This would never be helpful, since each such type has its own /// expression, and would not give a significant memory saving, since there /// is an Expr tree under each such type. +/// The instantiation-dependent-but-not-type-dependent DecltypeType node is an +/// exception, we unique it for forming correct substitutions in name mangling. 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 + // C++17 [temp.type]p2: + // If an expression e is type-dependent (17.6.2.2), 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()) { + // type only if their expressions are equivalent (17.5.6.1). + if (e->isTypeDependent()) { llvm::FoldingSetNodeID ID; DependentDecltypeType::Profile(ID, *this, e); @@ -5362,11 +5364,20 @@ Canon = new (*this, TypeAlignment) DependentDecltypeType(*this, e); DependentDecltypeTypes.InsertNode(Canon, InsertPos); } - dt = new (*this, TypeAlignment) - DecltypeType(e, UnderlyingType, QualType((DecltypeType *)Canon, 0)); + dt = new (*this, TypeAlignment) DecltypeType( + e, UnderlyingType, *this, QualType((DecltypeType *)Canon, 0)); + } else if (e->isInstantiationDependent()) { + llvm::FoldingSetNodeID ID; + DecltypeType::Profile(ID, *this, e); + void *InsertPos = nullptr; + if (DecltypeType *DT = DecltypeTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(DT, 0); + dt = new (*this, TypeAlignment) DecltypeType( + e, UnderlyingType, *this, getCanonicalType(UnderlyingType)); + DecltypeTypes.InsertNode(dt, InsertPos); } else { - dt = new (*this, TypeAlignment) - DecltypeType(e, UnderlyingType, getCanonicalType(UnderlyingType)); + dt = new (*this, TypeAlignment) DecltypeType( + e, UnderlyingType, *this, getCanonicalType(UnderlyingType)); } Types.push_back(dt); return QualType(dt, 0); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2527,6 +2527,8 @@ return true; if (Ty->isOpenCLSpecificType()) return true; + if (Ty->isDecltypeType() && Ty->isInstantiationDependentType()) + return true; if (Ty->isBuiltinType()) return false; // Through to Clang 6.0, we accidentally treated undeduced auto types as @@ -2582,6 +2584,12 @@ if (!TST->isTypeAlias()) break; + // Don't desugar through instantiation-dependent-but-not-type-dependent + // DecltypeType, as we want to mangle it as written. + if (const auto *DT = dyn_cast(T)) + if (!DT->isDependentType() && DT->isInstantiationDependentType()) + break; + QualType Desugared = T.getSingleStepDesugaredType(Context.getASTContext()); if (Desugared == T) diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3396,19 +3396,21 @@ E->Profile(ID, Context, true); } -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. +DecltypeType::DecltypeType(Expr *E, QualType underlyingType, + const ASTContext &Context, QualType can) + // C++17 [temp.type]p2: "If an expression e is type-dependent, decltype(e) + // denotes a unique dependent type." : Type(Decltype, can, - toTypeDependence(E->getDependence()) | - (E->isInstantiationDependent() ? TypeDependence::Dependent - : TypeDependence::None) | + // C++17 [temp.dep.type]p9: "denoted by decltype(expression), where + // expression is type-dependent" + (toTypeDependence(E->getDependence()) & ~TypeDependence::Dependent) | + (E->isTypeDependent() ? TypeDependence::Dependent + : TypeDependence::None) | (E->getType()->getDependence() & TypeDependence::VariablyModified)), - E(E), UnderlyingType(underlyingType) {} + E(E), UnderlyingType(underlyingType), Context(Context) {} -bool DecltypeType::isSugared() const { return !E->isInstantiationDependent(); } +bool DecltypeType::isSugared() const { return !E->isTypeDependent(); } QualType DecltypeType::desugar() const { if (isSugared()) @@ -3417,14 +3419,14 @@ return QualType(this, 0); } -DependentDecltypeType::DependentDecltypeType(const ASTContext &Context, Expr *E) - : DecltypeType(E, Context.DependentTy), Context(Context) {} - -void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, - const ASTContext &Context, Expr *E) { +void DecltypeType::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context, Expr *E) { E->Profile(ID, Context, true); } +DependentDecltypeType::DependentDecltypeType(const ASTContext &Context, Expr *E) + : DecltypeType(E, Context.DependentTy, Context) {} + UnaryTransformType::UnaryTransformType(QualType BaseType, QualType UnderlyingType, UTTKind UKind, QualType CanonicalType) diff --git a/clang/test/CodeGenCXX/mangle.cpp b/clang/test/CodeGenCXX/mangle.cpp --- a/clang/test/CodeGenCXX/mangle.cpp +++ b/clang/test/CodeGenCXX/mangle.cpp @@ -805,6 +805,10 @@ // CHECK-LABEL: define weak_odr void @_ZN6test341fIiEEvDTstDTplcvT__EcvS1__EEE template void f(decltype(sizeof(1))); + template void f(decltype(sizeof(T)), decltype(sizeof(T))) {} + // CHECK-LABEL: define weak_odr void @_ZN6test341fIiEEvDTstT_ES2_ + template void f(unsigned long, unsigned long); + // Mangling for non-instantiation-dependent sizeof expressions. template void f2(int (&)[N + sizeof(int*)]) {} diff --git a/clang/test/Sema/invalid-bitwidth-expr.mm b/clang/test/Sema/invalid-bitwidth-expr.mm --- a/clang/test/Sema/invalid-bitwidth-expr.mm +++ b/clang/test/Sema/invalid-bitwidth-expr.mm @@ -25,7 +25,8 @@ template auto func() { // error-bit should be propagated from TemplateArgument to NestNameSpecifier. - class Base::type C; // expected-error {{no matching function for call to 'Foo'}} + class Base::type C; // expected-error {{no matching function for call to 'Foo'}} \ + expected-error {{no class named 'type' in}} return C; } struct Z { diff --git a/clang/test/SemaCXX/invalid-template-base-specifier.cpp b/clang/test/SemaCXX/invalid-template-base-specifier.cpp --- a/clang/test/SemaCXX/invalid-template-base-specifier.cpp +++ b/clang/test/SemaCXX/invalid-template-base-specifier.cpp @@ -12,11 +12,12 @@ template using Alias = decltype(Foo(T())); // expected-error {{no matching function for call to 'Foo'}} template -struct Crash2 : decltype(Alias()) { // expected-note {{in instantiation of template type alias 'Alias' requested here}} +struct Crash2 : decltype(Alias()) { // expected-note {{in instantiation of template type alias 'Alias' requested here}} \ + expected-error {{base specifier must name a class}} Crash2(){}; }; -void test2() { Crash2(); } // expected-note {{in instantiation of template class 'Crash2' requested here}} +void test2() { Crash2(); } // expected-note2 {{in instantiation of template class 'Crash2' requested here}} template class Base {}; diff --git a/clang/test/SemaTemplate/dependent-expr.cpp b/clang/test/SemaTemplate/dependent-expr.cpp --- a/clang/test/SemaTemplate/dependent-expr.cpp +++ b/clang/test/SemaTemplate/dependent-expr.cpp @@ -129,7 +129,7 @@ template void f() { decltype(({})) x; // expected-error {{incomplete type}} } - template void f(); // expected-note {{instantiation of}} + template void f(); template 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 --- a/clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp +++ b/clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp @@ -115,6 +115,6 @@ int n; template struct SubstFailure; - TInt isf; // FIXME: this should be ill-formed + TInt isf; // expected-error {{template template argument has different template parameters than its corresponding template template parameter}} TIntPtr ipsf; }