hokein updated this revision to Diff 294143.
hokein marked 2 inline comments as done.
hokein added a comment.

store the actual expression in DecltypeTypeLoc and address comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87349/new/

https://reviews.llvm.org/D87349

Files:
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/AST/RecursiveASTVisitor.h
  clang/include/clang/AST/Type.h
  clang/include/clang/AST/TypeLoc.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/AST/ItaniumMangle.cpp
  clang/lib/AST/Type.cpp
  clang/lib/Sema/SemaCXXScopeSpec.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaType.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReader.cpp
  clang/lib/Serialization/ASTWriter.cpp
  clang/test/CodeGenCXX/mangle.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/unittests/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp

Index: clang/unittests/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp
===================================================================
--- clang/unittests/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp
+++ clang/unittests/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp
@@ -121,4 +121,18 @@
                               DeclRefExprVisitor::Lang_OBJCXX11));
 }
 
+TEST(RecursiveASTVisitor,
+     VisitInstantiationDependentDecltypeTypeUnderlyingExpr) {
+  DeclRefExprVisitor Visitor;
+  Visitor.ExpectMatch("x", 3, 57);
+  Visitor.ExpectMatch("x", 4, 57);
+  EXPECT_TRUE(Visitor.runOver(
+      R"cpp(
+      int x;
+      template<typename T> void f(decltype(sizeof(T().f(x))));
+      template<typename T> void g(decltype(sizeof(T().f(x))));
+    )cpp",
+      DeclRefExprVisitor::Lang_CXX17));
+}
+
 } // end anonymous namespace
Index: clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp
===================================================================
--- clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp
+++ clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp
@@ -115,6 +115,6 @@
 
   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 different template parameters than its corresponding template template parameter}}
   TIntPtr<SubstFailure> ipsf;
 }
Index: clang/test/SemaTemplate/dependent-expr.cpp
===================================================================
--- clang/test/SemaTemplate/dependent-expr.cpp
+++ clang/test/SemaTemplate/dependent-expr.cpp
@@ -129,7 +129,7 @@
   template<typename> void f() {
     decltype(({})) x; // expected-error {{incomplete type}}
   }
-  template void f<int>(); // expected-note {{instantiation of}}
+  template void f<int>();
 
   template<typename> auto g() {
     auto c = [](auto, int) -> decltype(({})) {};
Index: clang/test/SemaCXX/invalid-template-base-specifier.cpp
===================================================================
--- clang/test/SemaCXX/invalid-template-base-specifier.cpp
+++ clang/test/SemaCXX/invalid-template-base-specifier.cpp
@@ -12,11 +12,12 @@
 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-note2 {{in instantiation of template class 'Crash2<int>' requested here}}
 
 template <typename T>
 class Base {};
Index: clang/test/Sema/invalid-bitwidth-expr.mm
===================================================================
--- clang/test/Sema/invalid-bitwidth-expr.mm
+++ clang/test/Sema/invalid-bitwidth-expr.mm
@@ -25,7 +25,8 @@
 template <typename T>
 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'}}
+  class Base<decltype(Foo(T()))>::type C; // expected-error {{no matching function for call to 'Foo'}} \
+                                             expected-error {{no class named 'type' in}}
   return C;
 }
 struct Z {
Index: clang/test/CodeGenCXX/mangle.cpp
===================================================================
--- clang/test/CodeGenCXX/mangle.cpp
+++ clang/test/CodeGenCXX/mangle.cpp
@@ -805,6 +805,10 @@
   // CHECK-LABEL: define weak_odr void @_ZN6test341fIiEEvDTstDTplcvT__EcvS1__EEE
   template void f<int>(decltype(sizeof(1)));
 
+  template <typename T> void f(decltype(sizeof(T)), decltype(sizeof(T))) {}
+  // CHECK-LABEL: define weak_odr void @_ZN6test341fIiEEvDTstT_ES2_
+  template void f<int>(unsigned long, unsigned long);
+
   // Mangling for non-instantiation-dependent sizeof expressions.
   template<unsigned N>
   void f2(int (&)[N + sizeof(int*)]) {}
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -358,6 +358,7 @@
 
 void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
   Record.AddSourceLocation(TL.getNameLoc());
+  Record.AddStmt(TL.getUnderlyingExpr());
 }
 
 void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -6623,6 +6623,7 @@
 
 void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
   TL.setNameLoc(readSourceLocation());
+  TL.setUnderlyingExpr(Reader.readExpr());
 }
 
 void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -6051,7 +6051,11 @@
       SemaRef, Sema::ExpressionEvaluationContext::Unevaluated, nullptr,
       Sema::ExpressionEvaluationContextRecord::EK_Decltype);
 
-  ExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
+  // Prefer the underlying expression from the TypeLoc; the other may have been
+  // uniqued.
+  auto *UnderlyingExpr =
+      TL.getUnderlyingExpr() ? TL.getUnderlyingExpr() : T->getUnderlyingExpr();
+  ExprResult E = getDerived().TransformExpr(UnderlyingExpr);
   if (E.isInvalid())
     return QualType();
 
@@ -6061,7 +6065,7 @@
 
   QualType Result = TL.getType();
   if (getDerived().AlwaysRebuild() ||
-      E.get() != T->getUnderlyingExpr()) {
+      E.get() != UnderlyingExpr) {
     Result = getDerived().RebuildDecltypeType(E.get(), TL.getNameLoc());
     if (Result.isNull())
       return QualType();
@@ -6069,6 +6073,7 @@
   else E.get();
 
   DecltypeTypeLoc NewTL = TLB.push<DecltypeTypeLoc>(Result);
+  NewTL.setUnderlyingExpr(E.get());
   NewTL.setNameLoc(TL.getNameLoc());
 
   return Result;
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -5978,6 +5978,11 @@
       TL.setNameLoc(DS.getTypeSpecTypeLoc());
     }
 
+    void VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+      TL.setUnderlyingExpr(DS.getRepAsExpr());
+      TL.setNameLoc(DS.getTypeSpecTypeLoc());
+    }
+
     void VisitTypeLoc(TypeLoc TL) {
       // FIXME: add other typespec types and change this to an assert.
       TL.initialize(Context, DS.getTypeSpecTypeLoc());
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -7576,6 +7576,7 @@
   TypeLocBuilder TLB;
   DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
   DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc());
+  DecltypeTL.setUnderlyingExpr(DS.getRepAsExpr());
   TypeSourceInfo *DestructedTypeInfo = TLB.getTypeSourceInfo(Context, T);
   PseudoDestructorTypeStorage Destructed(DestructedTypeInfo);
 
Index: clang/lib/Sema/SemaCXXScopeSpec.cpp
===================================================================
--- clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -864,6 +864,7 @@
   TypeLocBuilder TLB;
   DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
   DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc());
+  DecltypeTL.setUnderlyingExpr(DS.getRepAsExpr());
   SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
             ColonColonLoc);
   return false;
Index: clang/lib/AST/Type.cpp
===================================================================
--- clang/lib/AST/Type.cpp
+++ clang/lib/AST/Type.cpp
@@ -3413,18 +3413,19 @@
 }
 
 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.
+    // 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) {}
 
-bool DecltypeType::isSugared() const { return !E->isInstantiationDependent(); }
+bool DecltypeType::isSugared() const { return !E->isTypeDependent(); }
 
 QualType DecltypeType::desugar() const {
   if (isSugared())
@@ -3433,14 +3434,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) {}
+
 UnaryTransformType::UnaryTransformType(QualType BaseType,
                                        QualType UnderlyingType, UTTKind UKind,
                                        QualType CanonicalType)
Index: clang/lib/AST/ItaniumMangle.cpp
===================================================================
--- clang/lib/AST/ItaniumMangle.cpp
+++ 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<DecltypeType>(T))
+        if (!DT->isDependentType() && DT->isInstantiationDependentType())
+          break;
+
       QualType Desugared
         = T.getSingleStepDesugaredType(Context.getASTContext());
       if (Desugared == T)
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -957,6 +957,7 @@
                        IdentifierTable &idents, SelectorTable &sels,
                        Builtin::Context &builtins)
     : ConstantArrayTypes(this_()), FunctionProtoTypes(this_()),
+      DependentDecltypeTypes(this_()), DecltypeTypes(this_()),
       TemplateSpecializationTypes(this_()),
       DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()),
       SubstTemplateTemplateParmPacks(this_()),
@@ -5340,17 +5341,18 @@
 }
 
 /// Unlike many "get<Type>" functions, we don't unique DecltypeType
-/// 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.
+/// nodes unless they are instantiation-dependent-but-not-type-dependent. 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.
 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);
 
@@ -5364,6 +5366,15 @@
     }
     dt = new (*this, TypeAlignment)
         DecltypeType(e, UnderlyingType, 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, getCanonicalType(UnderlyingType));
+    DecltypeTypes.InsertNode(dt, InsertPos);
   } else {
     dt = new (*this, TypeAlignment)
         DecltypeType(e, UnderlyingType, getCanonicalType(UnderlyingType));
Index: clang/include/clang/AST/TypeLoc.h
===================================================================
--- clang/include/clang/AST/TypeLoc.h
+++ clang/include/clang/AST/TypeLoc.h
@@ -1936,12 +1936,28 @@
   void initializeLocal(ASTContext &Context, SourceLocation Loc);
 };
 
+struct DecltypeTypeLocInfo {
+  Expr *UnderlyingExpr;
+  SourceLocation NameLoc;
+};
+
 // FIXME: location of the 'decltype' and parens.
-class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
-                                                         DecltypeTypeLoc,
-                                                         DecltypeType> {
+class DecltypeTypeLoc
+    : public ConcreteTypeLoc<UnqualTypeLoc, DecltypeTypeLoc, DecltypeType,
+                             DecltypeTypeLocInfo> {
 public:
-  Expr *getUnderlyingExpr() const { return getTypePtr()->getUnderlyingExpr(); }
+  Expr *getUnderlyingExpr() const { return getLocalData()->UnderlyingExpr; }
+  void setUnderlyingExpr(Expr *E) { getLocalData()->UnderlyingExpr = E; }
+  SourceLocation getNameLoc() const { return getLocalData()->NameLoc; }
+  SourceRange getLocalSourceRange() const {
+    return SourceRange(getNameLoc(), getNameLoc());
+  }
+  void setNameLoc(SourceLocation Loc) { getLocalData()->NameLoc = Loc; }
+
+  void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+    getLocalData()->NameLoc = Loc;
+    getLocalData()->UnderlyingExpr = nullptr;
+  }
 };
 
 struct UnaryTransformTypeLocInfo {
@@ -1951,10 +1967,9 @@
   TypeSourceInfo *UnderlyingTInfo;
 };
 
-class UnaryTransformTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
-                                                    UnaryTransformTypeLoc,
-                                                    UnaryTransformType,
-                                                    UnaryTransformTypeLocInfo> {
+class UnaryTransformTypeLoc
+    : public ConcreteTypeLoc<UnqualTypeLoc, UnaryTransformTypeLoc,
+                             UnaryTransformType, UnaryTransformTypeLocInfo> {
 public:
   SourceLocation getKWLoc() const { return getLocalData()->KWLoc; }
   void setKWLoc(SourceLocation Loc) { getLocalData()->KWLoc = Loc; }
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -4471,7 +4471,7 @@
 };
 
 /// Represents the type `decltype(expr)` (C++11).
-class DecltypeType : public Type {
+class DecltypeType : public Type, public llvm::FoldingSetNode {
   Expr *E;
   QualType UnderlyingType;
 
@@ -4491,6 +4491,12 @@
   bool isSugared() const;
 
   static bool classof(const Type *T) { return T->getTypeClass() == Decltype; }
+
+  void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) {
+    Profile(ID, Ctx, E);
+  }
+  static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+                      Expr *E);
 };
 
 /// Internal representation of canonical, dependent
@@ -4499,18 +4505,10 @@
 /// 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;
-
+/// FIXME: remove this in favor of DecltypeType.
+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.
Index: clang/include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- clang/include/clang/AST/RecursiveASTVisitor.h
+++ clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1252,7 +1252,9 @@
 
 // FIXME: location of underlying expr
 DEF_TRAVERSE_TYPELOC(DecltypeType, {
-  TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr()));
+  TRY_TO(TraverseStmt(TL.getUnderlyingExpr()
+                          ? TL.getUnderlyingExpr()
+                          : TL.getTypePtr()->getUnderlyingExpr()));
 })
 
 DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -202,7 +202,9 @@
   mutable llvm::ContextualFoldingSet<FunctionProtoType, ASTContext&>
     FunctionProtoTypes;
   mutable llvm::FoldingSet<DependentTypeOfExprType> DependentTypeOfExprTypes;
-  mutable llvm::FoldingSet<DependentDecltypeType> DependentDecltypeTypes;
+  mutable llvm::ContextualFoldingSet<DependentDecltypeType, ASTContext &>
+      DependentDecltypeTypes;
+  mutable llvm::ContextualFoldingSet<DecltypeType, ASTContext &> DecltypeTypes;
   mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
   mutable llvm::FoldingSet<ObjCTypeParamType> ObjCTypeParamTypes;
   mutable llvm::FoldingSet<SubstTemplateTypeParmType>
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to