mizvekov created this revision.
Herald added projects: clang, All.
Herald added a subscriber: cfe-commits.
mizvekov requested review of this revision.

Depends on D128095 <https://reviews.llvm.org/D128095>

Signed-off-by: Matheus Izvekov <mizve...@gmail.com>


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D130308

Files:
  clang/include/clang/AST/ASTContext.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/Sema/SemaTemplateDeduction.cpp
  clang/test/SemaCXX/sugar-common-types.cpp

Index: clang/test/SemaCXX/sugar-common-types.cpp
===================================================================
--- clang/test/SemaCXX/sugar-common-types.cpp
+++ clang/test/SemaCXX/sugar-common-types.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++20 -fenable-matrix
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++20 -fenable-matrix -triple i686-pc-win32
 
 enum class N {};
 
@@ -38,3 +38,61 @@
 N t7 = X4() + Y4(); // expected-error {{rvalue of type 'B4'}}
 N t8 = X4() * Y4(); // expected-error {{rvalue of type 'B4'}}
 N t9 = X5() * Y5(); // expected-error {{rvalue of type 'A4 __attribute__((matrix_type(3, 3)))'}}
+
+template <class T> struct S1 {
+  template <class U> struct S2 {};
+};
+
+N t10 = 0 ? S1<X1>() : S1<Y1>(); // expected-error {{from 'S1<B1>' (aka 'S1<int>')}}
+N t11 = 0 ? S1<X1>::S2<X2>() : S1<Y1>::S2<Y2>(); // expected-error {{from 'S1<int>::S2<B2>' (aka 'S2<void>')}}
+
+template <class T> using Al = S1<T>;
+
+N t12 = 0 ? Al<X1>() : Al<Y1>(); // expected-error {{from 'Al<B1>' (aka 'S1<int>')}}
+
+#define AS1 __attribute__((address_space(1)))
+#define AS2 __attribute__((address_space(1)))
+using AS1X1 = AS1 B1;
+using AS1Y1 = AS1 B1;
+using AS2Y1 = AS2 B1;
+N t13 = 0 ? (AS1X1){} : (AS1Y1){}; // expected-error {{rvalue of type 'AS1 B1' (aka '__attribute__((address_space(1))) int')}}
+N t14 = 0 ? (AS1X1){} : (AS2Y1){}; // expected-error {{rvalue of type '__attribute__((address_space(1))) B1' (aka '__attribute__((address_space(1))) int')}}
+
+using FX1 = X1 ();
+using FY1 = Y1 ();
+N t15 = 0 ? (FX1*){} : (FY1*){}; // expected-error {{rvalue of type 'B1 (*)()' (aka 'int (*)()')}}
+
+struct SS1 {};
+using SB1 = SS1;
+using SX1 = SB1;
+using SY1 = SB1;
+
+using MFX1 = X1 SX1::*();
+using MFY1 = Y1 SY1::*();
+
+N t16 = 0 ? (MFX1*){} : (MFY1*){}; // expected-error {{rvalue of type 'B1 SB1::*(*)()'}}
+
+N t17 = 0 ? (FX1 SX1::*){} : (FY1 SY1::*){}; // expected-error {{rvalue of type 'B1 (SB1::*)() __attribute__((thiscall))'}}
+
+N t18 = 0 ? (__typeof(X1*)){} : (__typeof(Y1*)){}; // expected-error {{rvalue of type 'typeof(B1 *)' (aka 'int *')}}
+
+struct Enums {
+  enum X : B1;
+  enum Y : ::B1;
+};
+using EnumsB = Enums;
+using EnumsX = EnumsB;
+using EnumsY = EnumsB;
+
+N t19 = 0 ? (__underlying_type(EnumsX::X)){} : (__underlying_type(EnumsY::Y)){};
+// expected-error@-1 {{rvalue of type 'B1' (aka 'int')}}
+
+N t20 = 0 ? (__underlying_type(EnumsX::X)){} : (__underlying_type(EnumsY::X)){};
+// expected-error@-1 {{rvalue of type '__underlying_type(Enums::X)' (aka 'int')}}
+
+using SBTF1 = SS1 [[clang::btf_type_tag("1")]];
+using SBTF2 = ::SS1 [[clang::btf_type_tag("1")]];
+using SBTF3 = ::SS1 [[clang::btf_type_tag("2")]];
+
+N t21 = 0 ? (SBTF1){} : (SBTF3){}; // expected-error {{from 'SS1'}}
+N t22 = 0 ? (SBTF1){} : (SBTF2){}; // expected-error {{from 'SS1 btf_type_tag(1)' (aka 'SS1')}}
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3776,13 +3776,11 @@
     //   - If A is an array type, the pointer type produced by the
     //     array-to-pointer standard conversion (4.2) is used in place of
     //     A for type deduction; otherwise,
-    if (ArgType->isArrayType())
-      ArgType = S.Context.getArrayDecayedType(ArgType);
     //   - If A is a function type, the pointer type produced by the
     //     function-to-pointer standard conversion (4.3) is used in place
     //     of A for type deduction; otherwise,
-    else if (ArgType->isFunctionType())
-      ArgType = S.Context.getPointerType(ArgType);
+    if (ArgType->canDecayToPointerType())
+      ArgType = S.Context.getDecayedType(ArgType);
     else {
       // - If A is a cv-qualified type, the top level cv-qualifiers of A's
       //   type are ignored for type deduction.
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -3329,6 +3329,26 @@
   return QualType(AT, 0);
 }
 
+QualType ASTContext::getDecayedType(QualType T, QualType Decayed) const {
+  llvm::FoldingSetNodeID ID;
+  AdjustedType::Profile(ID, T, Decayed);
+  void *InsertPos = nullptr;
+  AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
+  if (AT)
+    return QualType(AT, 0);
+
+  QualType Canonical = getCanonicalType(Decayed);
+
+  // Get the new insert position for the node we care about.
+  AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
+  assert(!AT && "Shouldn't be in the map!");
+
+  AT = new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical);
+  Types.push_back(AT);
+  AdjustedTypes.InsertNode(AT, InsertPos);
+  return QualType(AT, 0);
+}
+
 QualType ASTContext::getDecayedType(QualType T) const {
   assert((T->isArrayType() || T->isFunctionType()) && "T does not decay");
 
@@ -3349,23 +3369,7 @@
   if (T->isFunctionType())
     Decayed = getPointerType(T);
 
-  llvm::FoldingSetNodeID ID;
-  AdjustedType::Profile(ID, T, Decayed);
-  void *InsertPos = nullptr;
-  AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
-  if (AT)
-    return QualType(AT, 0);
-
-  QualType Canonical = getCanonicalType(Decayed);
-
-  // Get the new insert position for the node we care about.
-  AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
-  assert(!AT && "Shouldn't be in the map!");
-
-  AT = new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical);
-  Types.push_back(AT);
-  AdjustedTypes.InsertNode(AT, InsertPos);
-  return QualType(AT, 0);
+  return getDecayedType(T, Decayed);
 }
 
 /// getBlockPointerType - Return the uniqued reference to the type for
@@ -12107,7 +12111,8 @@
 static Decl *getCommonDecl(Decl *X, Decl *Y) {
   if (X == Y)
     return X;
-  assert(declaresSameEntity(X, Y));
+  if (!declaresSameEntity(X, Y))
+    return nullptr;
   for (auto DX : X->redecls()) {
     // If we reach Y before reaching the canonical Decl, that means X is older.
     if (DX == Y)
@@ -12127,6 +12132,13 @@
                     const_cast<Decl *>(cast_or_null<Decl>(Y))));
 }
 
+template <class T,
+          std::enable_if_t<std::is_base_of<Decl, T>::value, bool> = true>
+T *getCommonDeclChecked(T *X, T *Y) {
+  return cast<T>(getCommonDecl(const_cast<Decl *>(cast<Decl>(X)),
+                               const_cast<Decl *>(cast<Decl>(Y))));
+}
+
 static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X,
                                           TemplateName Y) {
   if (X.getAsVoidPointer() == Y.getAsVoidPointer())
@@ -12306,7 +12318,22 @@
   llvm_unreachable("invalid ExceptionSpecificationType");
 }
 
-static QualType getCommonType(ASTContext &Ctx, const Type *X, const Type *Y) {
+static QualType getCommonTemplateSpecializationType(ASTContext &Ctx,
+                                                    const Type *X,
+                                                    const Type *Y,
+                                                    QualType Underlying) {
+  const auto *TX = cast<TemplateSpecializationType>(X),
+             *TY = cast<TemplateSpecializationType>(Y);
+  auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
+                                       TY->template_arguments());
+  return Ctx.getTemplateSpecializationType(
+      ::getCommonTemplateName(Ctx, TX->getTemplateName(),
+                              TY->getTemplateName()),
+      As, Underlying);
+}
+
+static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
+                                          const Type *Y) {
   Type::TypeClass TC = X->getTypeClass();
   assert(TC == Y->getTypeClass());
   switch (TC) {
@@ -12352,8 +12379,8 @@
     return Ctx.getAutoType(QualType(), AX->getKeyword(),
                            AX->isInstantiationDependentType(),
                            AX->containsUnexpandedParameterPack(),
-                           getCommonDecl(AX->getTypeConstraintConcept(),
-                                         AY->getTypeConstraintConcept()),
+                           getCommonDeclChecked(AX->getTypeConstraintConcept(),
+                                                AY->getTypeConstraintConcept()),
                            As);
   }
   case Type::IncompleteArray: {
@@ -12525,20 +12552,13 @@
     const auto *IX = cast<InjectedClassNameType>(X),
                *IY = cast<InjectedClassNameType>(Y);
     return Ctx.getInjectedClassNameType(
-        getCommonDecl(IX->getDecl(), IY->getDecl()),
+        getCommonDeclChecked(IX->getDecl(), IY->getDecl()),
         Ctx.getCommonSugaredType(IX->getInjectedSpecializationType(),
                                  IY->getInjectedSpecializationType()));
   }
-  case Type::TemplateSpecialization: {
-    const auto *TX = cast<TemplateSpecializationType>(X),
-               *TY = cast<TemplateSpecializationType>(Y);
-    auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
-                                         TY->template_arguments());
-    return Ctx.getTemplateSpecializationType(
-        ::getCommonTemplateName(Ctx, TX->getTemplateName(),
-                                TY->getTemplateName()),
-        As, TX->getCanonicalTypeInternal());
-  }
+  case Type::TemplateSpecialization:
+    return ::getCommonTemplateSpecializationType(Ctx, X, Y,
+                                                 X->getCanonicalTypeInternal());
   case Type::DependentName: {
     const auto *NX = cast<DependentNameType>(X),
                *NY = cast<DependentNameType>(Y);
@@ -12585,6 +12605,173 @@
   llvm_unreachable("Unknown Type Class");
 }
 
+static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
+                                       const Type *Y, QualType Underlying) {
+  Type::TypeClass TC = X->getTypeClass();
+  if (TC != Y->getTypeClass())
+    return QualType();
+  switch (TC) {
+#define UNEXPECTED_TYPE(Class, Kind)                                           \
+  case Type::Class:                                                            \
+    llvm_unreachable("Unexpected " Kind ": " #Class);
+#define TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) UNEXPECTED_TYPE(Class, "dependent")
+#include "clang/AST/TypeNodes.inc"
+
+#define CANONICAL_TYPE(Class) UNEXPECTED_TYPE(Class, "canonical")
+    CANONICAL_TYPE(Atomic)
+    CANONICAL_TYPE(BitInt)
+    CANONICAL_TYPE(BlockPointer)
+    CANONICAL_TYPE(Builtin)
+    CANONICAL_TYPE(Complex)
+    CANONICAL_TYPE(ConstantArray)
+    CANONICAL_TYPE(ConstantMatrix)
+    CANONICAL_TYPE(Enum)
+    CANONICAL_TYPE(ExtVector)
+    CANONICAL_TYPE(FunctionNoProto)
+    CANONICAL_TYPE(FunctionProto)
+    CANONICAL_TYPE(IncompleteArray)
+    CANONICAL_TYPE(LValueReference)
+    CANONICAL_TYPE(MemberPointer)
+    CANONICAL_TYPE(ObjCInterface)
+    CANONICAL_TYPE(ObjCObject)
+    CANONICAL_TYPE(ObjCObjectPointer)
+    CANONICAL_TYPE(Pipe)
+    CANONICAL_TYPE(Pointer)
+    CANONICAL_TYPE(Record)
+    CANONICAL_TYPE(RValueReference)
+    CANONICAL_TYPE(VariableArray)
+    CANONICAL_TYPE(Vector)
+#undef CANONICAL_TYPE
+
+#undef UNEXPECTED_TYPE
+
+  case Type::Adjusted: {
+    const auto *AX = cast<AdjustedType>(X), *AY = cast<AdjustedType>(Y);
+    QualType OX = AX->getOriginalType(), OY = AY->getOriginalType();
+    if (!Ctx.hasSameType(OX, OY))
+      return QualType();
+    // FIXME: It's inneficient to have to unify the original types.
+    return Ctx.getAdjustedType(Ctx.getCommonSugaredType(OX, OY), Underlying);
+  }
+  case Type::Decayed: {
+    const auto *DX = cast<DecayedType>(X), *DY = cast<DecayedType>(Y);
+    QualType OX = DX->getOriginalType(), OY = DY->getOriginalType();
+    if (!Ctx.hasSameType(OX, OY))
+      return QualType();
+    // FIXME: It's inneficient to have to unify the original types.
+    return Ctx.getDecayedType(Ctx.getCommonSugaredType(OX, OY), Underlying);
+  }
+  case Type::Attributed: {
+    const auto *AX = cast<AttributedType>(X), *AY = cast<AttributedType>(Y);
+    AttributedType::Kind Kind = AX->getAttrKind();
+    if (Kind != AY->getAttrKind())
+      return QualType();
+    // FIXME: The modified types can be different as well.
+    // FIXME: It's inneficient to have to unify the modified types.
+    return Ctx.getAttributedType(
+        Kind,
+        Ctx.getCommonSugaredType(AX->getModifiedType(), AY->getModifiedType()),
+        Underlying);
+  }
+  case Type::BTFTagAttributed: {
+    const auto *BX = cast<BTFTagAttributedType>(X);
+    const BTFTypeTagAttr *AX = BX->getAttr();
+    // The attribute is not uniqued, so just compare the tag.
+    if (AX->getBTFTypeTag() !=
+        cast<BTFTagAttributedType>(Y)->getAttr()->getBTFTypeTag())
+      return QualType();
+    return Ctx.getBTFTagAttributedType(AX, Underlying);
+  }
+  case Type::Auto: {
+    const auto *AX = cast<AutoType>(X), *AY = cast<AutoType>(Y);
+    AutoTypeKeyword KW = AX->getKeyword();
+    if (KW != AY->getKeyword())
+      return QualType();
+    ConceptDecl *CD = ::getCommonDecl(AX->getTypeConstraintConcept(),
+                                      AY->getTypeConstraintConcept());
+    SmallVector<TemplateArgument, 8> As;
+    if (CD)
+      As = getCommonTemplateArguments(Ctx, AX->getTypeConstraintArguments(),
+                                      AY->getTypeConstraintArguments());
+    return Ctx.getAutoType(Underlying, AX->getKeyword(),
+                           AX->isInstantiationDependentType(),
+                           AX->containsUnexpandedParameterPack(), CD, As);
+  }
+  case Type::Decltype:
+    return QualType();
+  case Type::DeducedTemplateSpecialization:
+    // FIXME: Try to merge these.
+    return QualType();
+  case Type::Elaborated: {
+    const auto *EX = cast<ElaboratedType>(X), *EY = cast<ElaboratedType>(Y);
+    return Ctx.getElaboratedType(
+        ::getCommonTypeKeyword(EX, EY), ::getCommonNNS(Ctx, EX, EY), Underlying,
+        ::getCommonDecl(EX->getOwnedTagDecl(), EY->getOwnedTagDecl()));
+  }
+  case Type::MacroQualified: {
+    const auto *MX = cast<MacroQualifiedType>(X),
+               *MY = cast<MacroQualifiedType>(Y);
+    const IdentifierInfo *IX = MX->getMacroIdentifier();
+    if (IX != MY->getMacroIdentifier())
+      return QualType();
+    return Ctx.getMacroQualifiedType(Underlying, IX);
+  }
+  case Type::SubstTemplateTypeParm: {
+    const auto *SX = cast<SubstTemplateTypeParmType>(X),
+               *SY = cast<SubstTemplateTypeParmType>(Y);
+    auto PackIndex = SX->getPackIndex();
+    if (PackIndex != SY->getPackIndex())
+      return QualType();
+    const TemplateTypeParmType *PX = SX->getReplacedParameter();
+    if (PX != SY->getReplacedParameter())
+      return QualType();
+    return Ctx.getSubstTemplateTypeParmType(PX, Underlying, PackIndex);
+  }
+  case Type::ObjCTypeParam:
+    // FIXME: Try to merge these.
+    return QualType();
+  case Type::Paren:
+    return Ctx.getParenType(Underlying);
+  case Type::TemplateSpecialization:
+    return ::getCommonTemplateSpecializationType(Ctx, X, Y, Underlying);
+  case Type::Typedef: {
+    const auto *TX = cast<TypedefType>(X), *TY = cast<TypedefType>(Y);
+    const TypedefNameDecl *DX = TX->getDecl(), *DY = TY->getDecl();
+    assert(DX != DY);
+    if (!declaresSameEntity(DX, DY))
+      return QualType();
+    return Ctx.getTypedefType(::getCommonDecl(DX, DY), Underlying);
+  }
+  case Type::TypeOf:
+    return Ctx.getTypeOfType(Underlying);
+  case Type::TypeOfExpr:
+    return QualType();
+  case Type::UnaryTransform: {
+    const auto *UX = cast<UnaryTransformType>(X),
+               *UY = cast<UnaryTransformType>(Y);
+    UnaryTransformType::UTTKind KX = UX->getUTTKind();
+    if (KX != UY->getUTTKind())
+      return QualType();
+    QualType BX = UX->getBaseType(), BY = UY->getBaseType();
+    if (!Ctx.hasSameType(BX, BY))
+      return QualType();
+    // FIXME: It's inneficient to have to unify the base types.
+    return Ctx.getUnaryTransformType(Ctx.getCommonSugaredType(BX, BY),
+                                     Underlying, KX);
+  }
+  case Type::Using: {
+    const auto *UX = cast<UsingType>(X), *UY = cast<UsingType>(Y);
+    const UsingShadowDecl *DX = UX->getFoundDecl(), *DY = UY->getFoundDecl();
+    assert(DX != DY);
+    if (!declaresSameEntity(DX, DY))
+      return QualType();
+    return Ctx.getUsingType(::getCommonDecl(DX, DY), Underlying);
+  }
+  }
+  llvm_unreachable("Unhandled Type Class");
+}
+
 static auto unwrapSugar(SplitQualType &T) {
   SmallVector<SplitQualType, 8> R;
   while (true) {
@@ -12599,17 +12786,6 @@
   return R;
 }
 
-static bool removeDifferentTopLevelSugar(SplitQualType &SX, SplitQualType &SY) {
-  auto Xs = ::unwrapSugar(SX), Ys = ::unwrapSugar(SY);
-  if (SX.Ty != SY.Ty)
-    return true;
-  while (!Xs.empty() && !Ys.empty() && Xs.back().Ty == Ys.back().Ty) {
-    SX = Xs.pop_back_val();
-    SY = Ys.pop_back_val();
-  }
-  return false;
-}
-
 QualType ASTContext::getCommonSugaredType(QualType X, QualType Y,
                                           bool Unqualified) {
   assert(Unqualified ? hasSameUnqualifiedType(X, Y) : hasSameType(X, Y));
@@ -12623,15 +12799,30 @@
   }
 
   SplitQualType SX = X.split(), SY = Y.split();
-  if (::removeDifferentTopLevelSugar(SX, SY))
-    SX.Ty = ::getCommonType(*this, SX.Ty, SY.Ty).getTypePtr();
-
-  if (Unqualified)
-    SX.Quals = Qualifiers::removeCommonQualifiers(SX.Quals, SY.Quals);
-  else
-    assert(SX.Quals == SY.Quals);
-
-  QualType R = getQualifiedType(SX);
+  auto Xs = ::unwrapSugar(SX), Ys = ::unwrapSugar(SY);
+  if (SX.Ty != SY.Ty) {
+    SX.Ty = ::getCommonNonSugarTypeNode(*this, SX.Ty, SY.Ty).getTypePtr();
+  } else {
+    while (!Xs.empty() && !Ys.empty() && Xs.back().Ty == Ys.back().Ty) {
+      SX = Xs.pop_back_val();
+      SY = Ys.pop_back_val();
+    }
+  }
+  QualType R;
+  for (;;) {
+    if (Unqualified)
+      SX.Quals = Qualifiers::removeCommonQualifiers(SX.Quals, SY.Quals);
+    else
+      assert(SX.Quals == SY.Quals);
+    R = getQualifiedType(SX);
+    if (Xs.empty() || Ys.empty())
+      break;
+    SX = Xs.pop_back_val();
+    SY = Ys.pop_back_val();
+    SX.Ty = ::getCommonSugarTypeNode(*this, SX.Ty, SY.Ty, R).getTypePtrOrNull();
+    if (!SX.Ty)
+      break;
+  }
   assert(Unqualified ? hasSameUnqualifiedType(R, X) : hasSameType(R, X));
   return R;
 }
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -1357,6 +1357,7 @@
   CanQualType getDecayedType(CanQualType T) const {
     return CanQualType::CreateUnsafe(getDecayedType((QualType) T));
   }
+  QualType getDecayedType(QualType T, QualType Decayed) const;
 
   /// Return the uniqued reference to the atomic type for the specified
   /// type.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D130308: ... Matheus Izvekov via Phabricator via cfe-commits

Reply via email to