Skip to content

[clang] AST: fix dependency calculation for TypedefTypes #143291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 8, 2025

Conversation

mizvekov
Copy link
Contributor

@mizvekov mizvekov commented Jun 8, 2025

The dependency from the type sugar of the underlying type of a Typedef were not being considered for the dependency of the TypedefType itself.

A TypedefType should be instantiation dependent if it involves non-instantiated template parameters, even if they don't contribute to the canonical type.

Besides, a TypedefType should be instantiation dependent if it is declared in a dependent context, but fixing that would have performance consequences, as otherwise non-dependent typedef declarations would need to be transformed during instantiation as well.

This removes the workaround added in #90032

Fixes #89774

@mizvekov mizvekov self-assigned this Jun 8, 2025
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. debuginfo labels Jun 8, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 8, 2025

@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-debuginfo

@llvm/pr-subscribers-clang

Author: Matheus Izvekov (mizvekov)

Changes

The dependency from the type sugar of the underlying type of a Typedef were not being considered for the dependency of the TypedefType itself.

A TypedefType should be instantiation dependent if it involves non-instantiated template parameters, even if they don't contribute to the canonical type.

Besides, a TypedefType should be instantiation dependent if it is declared in a dependent context, but fixing that would have performance consequences, as otherwise non-dependent typedef declarations would need to be transformed during instantiation as well.

This removes the workaround added in #90032

Fixes #89774


Full diff: https://github.com/llvm/llvm-project/pull/143291.diff

6 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+2-1)
  • (modified) clang/include/clang/AST/Type.h (+2-2)
  • (modified) clang/lib/AST/ASTContext.cpp (+2-2)
  • (modified) clang/lib/AST/Type.cpp (+5-5)
  • (modified) clang/lib/CodeGen/CGDebugInfo.cpp (+1-22)
  • (modified) clang/test/CodeGenCXX/dependent-template-alias.cpp (+2-5)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1dd8b794c943a..322686fce0b04 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -687,7 +687,7 @@ Bug Fixes in This Version
 - Fixed an assertion failure in serialization of constexpr structs containing unions. (#GH140130)
 - Fixed duplicate entries in TableGen that caused the wrong attribute to be selected. (GH#140701)
 - Fixed type mismatch error when 'builtin-elementwise-math' arguments have different qualifiers, this should be well-formed. (#GH141397)
-- Constant evaluation now correctly runs the destructor of a variable declared in 
+- Constant evaluation now correctly runs the destructor of a variable declared in
   the second clause of a C-style ``for`` loop. (#GH139818)
 
 Bug Fixes to Compiler Builtins
@@ -843,6 +843,7 @@ Bug Fixes to AST Handling
 - Fixed uninitialized use check in a lambda within CXXOperatorCallExpr. (#GH129198)
 - Fixed a malformed printout of ``CXXParenListInitExpr`` in certain contexts.
 - Fixed a malformed printout of certain calling convention function attributes. (#GH143160)
+- Fixed dependency calculation for TypedefTypes (#GH89774)
 
 Miscellaneous Bug Fixes
 ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index a6c26a07800c3..040edd392b7aa 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -5821,8 +5821,8 @@ class TypedefType final : public Type,
   friend class ASTContext; // ASTContext creates these.
   friend TrailingObjects;
 
-  TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType underlying,
-              QualType can);
+  TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType UnderlyingType,
+              bool HasTypeDifferentFromDecl);
 
 public:
   TypedefNameDecl *getDecl() const { return Decl; }
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 45f9602856840..b51f7622288df 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5216,7 +5216,7 @@ QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl,
     if (Underlying.isNull())
       Underlying = Decl->getUnderlyingType();
     auto *NewType = new (*this, alignof(TypedefType)) TypedefType(
-        Type::Typedef, Decl, QualType(), getCanonicalType(Underlying));
+        Type::Typedef, Decl, Underlying, /*HasTypeDifferentFromDecl=*/false);
     Decl->TypeForDecl = NewType;
     Types.push_back(NewType);
     return QualType(NewType, 0);
@@ -5238,7 +5238,7 @@ QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl,
   void *Mem = Allocate(TypedefType::totalSizeToAlloc<QualType>(true),
                        alignof(TypedefType));
   auto *NewType = new (Mem) TypedefType(Type::Typedef, Decl, Underlying,
-                                        getCanonicalType(Underlying));
+                                        /*HasTypeDifferentFromDecl=*/true);
   TypedefTypes.InsertNode(NewType, InsertPos);
   Types.push_back(NewType);
   return QualType(NewType, 0);
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 5bb39b12693fb..49f5e8138834b 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4013,13 +4013,13 @@ StringRef CountAttributedType::getAttributeName(bool WithMacroPrefix) const {
 }
 
 TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D,
-                         QualType Underlying, QualType can)
-    : Type(tc, can, toSemanticDependence(can->getDependence())),
+                         QualType UnderlyingType, bool HasTypeDifferentFromDecl)
+    : Type(tc, UnderlyingType.getCanonicalType(),
+           toSemanticDependence(UnderlyingType->getDependence())),
       Decl(const_cast<TypedefNameDecl *>(D)) {
-  assert(!isa<TypedefType>(can) && "Invalid canonical type");
-  TypedefBits.hasTypeDifferentFromDecl = !Underlying.isNull();
+  TypedefBits.hasTypeDifferentFromDecl = HasTypeDifferentFromDecl;
   if (!typeMatchesDecl())
-    *getTrailingObjects<QualType>() = Underlying;
+    *getTrailingObjects<QualType>() = UnderlyingType;
 }
 
 QualType TypedefType::desugar() const {
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 001b208e1c3ff..ee5e3d68a5ffa 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1564,28 +1564,7 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
 
   SourceLocation Loc = AliasDecl->getLocation();
 
-  if (CGM.getCodeGenOpts().DebugTemplateAlias &&
-      // FIXME: This is a workaround for the issue
-      //        https://github.com/llvm/llvm-project/issues/89774
-      // The TemplateSpecializationType doesn't contain any instantiation
-      // information; dependent template arguments can't be resolved. For now,
-      // fall back to DW_TAG_typedefs for template aliases that are
-      // instantiation dependent, e.g.:
-      // ```
-      // template <int>
-      // using A = int;
-      //
-      // template<int I>
-      // struct S {
-      //   using AA = A<I>; // Instantiation dependent.
-      //   AA aa;
-      // };
-      //
-      // S<0> s;
-      // ```
-      // S::AA's underlying type A<I> is dependent on I so will be emitted as a
-      // DW_TAG_typedef.
-      !Ty->isInstantiationDependentType()) {
+  if (CGM.getCodeGenOpts().DebugTemplateAlias) {
     auto ArgVector = ::GetTemplateArgs(TD, Ty);
     TemplateArgs Args = {TD->getTemplateParameters(), ArgVector};
 
diff --git a/clang/test/CodeGenCXX/dependent-template-alias.cpp b/clang/test/CodeGenCXX/dependent-template-alias.cpp
index deb243f9fc88d..324b16f1919df 100644
--- a/clang/test/CodeGenCXX/dependent-template-alias.cpp
+++ b/clang/test/CodeGenCXX/dependent-template-alias.cpp
@@ -1,9 +1,6 @@
 // RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone -gtemplate-alias %s -gsimple-template-names=simple \
 // RUN: | FileCheck %s
 
-//// Check that -gtemplate-alias falls back to DW_TAG_typedef emission
-//// for instantiation dependent type aliases.
-
 template <int>
 using A = int;
 
@@ -16,6 +13,6 @@ struct S {
 S<0> s;
 
 // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "aa", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[AA:[0-9]+]], size: 32)
-// CHECK: [[AA]] = !DIDerivedType(tag: DW_TAG_typedef, name: "AA", file: ![[#]], line: [[#]], baseType: ![[A:[0-9]+]])
-// CHECK: [[A]] = !DIDerivedType(tag: DW_TAG_typedef, name: "A<I>", file: ![[#]], line: [[#]], baseType: ![[int:[0-9]+]])
+// CHECK: [[AA]] = !DIDerivedType(tag: DW_TAG_typedef, name: "AA", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[A:[0-9]+]])
+// CHECK: [[A]] = !DIDerivedType(tag: DW_TAG_template_alias, name: "A", file: ![[#]], line: [[#]], baseType: ![[int:[0-9]+]], extraData: ![[#]])
 // CHECK: [[int]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)

Copy link
Contributor

@zyn0217 zyn0217 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

The dependency from the type sugar of the underlying type of a
Typedef were not being considered for the dependency of the TypedefType
itself.

A TypedefType should be instantiation dependent if it involves
non-instantiated template parameters, even if they don't contribute
to the canonical type.

Besides, a TypedefType should be instantiation dependent if it is
declared in a dependent context, but fixing that would have
performance consequences, as otherwise non-dependent typedef
declarations would need to be transformed during instantiation as well.

This removes the workaround added in #90032

Fixes #89774
@mizvekov mizvekov force-pushed the users/mizvekov/GH89774 branch from 6ef4b07 to d623054 Compare June 8, 2025 19:00
@mizvekov mizvekov merged commit 366f488 into main Jun 8, 2025
8 checks passed
@mizvekov mizvekov deleted the users/mizvekov/GH89774 branch June 8, 2025 20:07
rorth pushed a commit to rorth/llvm-project that referenced this pull request Jun 11, 2025
The dependency from the type sugar of the underlying type of a Typedef
were not being considered for the dependency of the TypedefType itself.

A TypedefType should be instantiation dependent if it involves
non-instantiated template parameters, even if they don't contribute to
the canonical type.

Besides, a TypedefType should be instantiation dependent if it is
declared in a dependent context, but fixing that would have performance
consequences, as otherwise non-dependent typedef declarations would need
to be transformed during instantiation as well.

This removes the workaround added in
llvm#90032

Fixes llvm#89774
DhruvSrivastavaX pushed a commit to DhruvSrivastavaX/lldb-for-aix that referenced this pull request Jun 12, 2025
The dependency from the type sugar of the underlying type of a Typedef
were not being considered for the dependency of the TypedefType itself.

A TypedefType should be instantiation dependent if it involves
non-instantiated template parameters, even if they don't contribute to
the canonical type.

Besides, a TypedefType should be instantiation dependent if it is
declared in a dependent context, but fixing that would have performance
consequences, as otherwise non-dependent typedef declarations would need
to be transformed during instantiation as well.

This removes the workaround added in
llvm#90032

Fixes llvm#89774
tomtor pushed a commit to tomtor/llvm-project that referenced this pull request Jun 14, 2025
The dependency from the type sugar of the underlying type of a Typedef
were not being considered for the dependency of the TypedefType itself.

A TypedefType should be instantiation dependent if it involves
non-instantiated template parameters, even if they don't contribute to
the canonical type.

Besides, a TypedefType should be instantiation dependent if it is
declared in a dependent context, but fixing that would have performance
consequences, as otherwise non-dependent typedef declarations would need
to be transformed during instantiation as well.

This removes the workaround added in
llvm#90032

Fixes llvm#89774
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category debuginfo
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Clang] -gtemplate-alias assertion failure '!isValueDependent() && "Expression evaluator can't be called on a dependent expression."'
4 participants