Skip to content
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

[Clang] [c++20] P1907R1: Support for generalized non-type template ar… #77428

Closed
wants to merge 1 commit into from

Conversation

cor3ntin
Copy link
Contributor

@cor3ntin cor3ntin commented Jan 9, 2024

…guments of scalar type

Initially https://reviews.llvm.org/D140996

Author: @bolshakov-a

I do not plan to work on this, but I'm trying to salvage what I can from phabricator. This review, is completely gone. I extracted it from my mails. So this PR is purely to make sure we have a trace.

…guments of scalar type

Initially https://reviews.llvm.org/D140996

Author: @bolshakov-a

I do not plan to work on this, but I'm trying to salvage what I can from phabricator.
This review, is completely gone. I extracted it from my mails.
So this PR is purely to make sure we have a trace.
@llvmbot llvmbot added clang Clang issues not falling into any other category lldb clangd clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang:codegen debuginfo labels Jan 9, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Jan 9, 2024

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

@llvm/pr-subscribers-clang

Author: cor3ntin (cor3ntin)

Changes

…guments of scalar type

Initially https://reviews.llvm.org/D140996

Author: @bolshakov-a

I do not plan to work on this, but I'm trying to salvage what I can from phabricator. This review, is completely gone. I extracted it from my mails. So this PR is purely to make sure we have a trace.


Patch is 91.37 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/77428.diff

43 Files Affected:

  • (modified) clang-tools-extra/clangd/DumpAST.cpp (+1)
  • (modified) clang-tools-extra/clangd/FindTarget.cpp (+1)
  • (modified) clang/docs/ReleaseNotes.rst (+2)
  • (modified) clang/include/clang/AST/ODRHash.h (+3)
  • (modified) clang/include/clang/AST/PropertiesBase.td (+14)
  • (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+2)
  • (modified) clang/include/clang/AST/TemplateArgumentVisitor.h (+2)
  • (modified) clang/include/clang/AST/TemplateBase.h (+53-31)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2-5)
  • (modified) clang/include/clang/Sema/Sema.h (+2-2)
  • (modified) clang/lib/AST/ASTContext.cpp (+5)
  • (modified) clang/lib/AST/ASTImporter.cpp (+13)
  • (modified) clang/lib/AST/ASTStructuralEquivalence.cpp (+4)
  • (modified) clang/lib/AST/Decl.cpp (+4)
  • (modified) clang/lib/AST/ItaniumMangle.cpp (+37-2)
  • (modified) clang/lib/AST/MicrosoftMangle.cpp (+62-16)
  • (modified) clang/lib/AST/ODRHash.cpp (+72)
  • (modified) clang/lib/AST/StmtProfile.cpp (+6)
  • (modified) clang/lib/AST/TemplateBase.cpp (+110-3)
  • (modified) clang/lib/AST/TypeLoc.cpp (+1)
  • (modified) clang/lib/CodeGen/CGDebugInfo.cpp (+8)
  • (modified) clang/lib/Index/USRGeneration.cpp (+10)
  • (modified) clang/lib/Sema/SemaLookup.cpp (+1)
  • (modified) clang/lib/Sema/SemaOverload.cpp (+9)
  • (modified) clang/lib/Sema/SemaTemplate.cpp (+129-87)
  • (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+46-18)
  • (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+6-8)
  • (modified) clang/lib/Sema/SemaTemplateVariadic.cpp (+2)
  • (modified) clang/lib/Sema/TreeTransform.h (+10-2)
  • (modified) clang/lib/Serialization/ASTReader.cpp (+1)
  • (modified) clang/lib/Serialization/ASTWriter.cpp (+1)
  • (modified) clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp (+3-1)
  • (modified) clang/test/CodeGenCXX/mangle-ms-templates.cpp (+48)
  • (modified) clang/test/CodeGenCXX/mangle-template.cpp (+39-1)
  • (modified) clang/test/Modules/odr_hash.cpp (+190-3)
  • (modified) clang/test/SemaCXX/warn-bool-conversion.cpp (+2)
  • (modified) clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp (+19-21)
  • (modified) clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp (+22-18)
  • (modified) clang/tools/libclang/CIndex.cpp (+5)
  • (modified) clang/tools/libclang/CXCursor.cpp (+3)
  • (modified) clang/www/cxx_status.html (+13-5)
  • (modified) lldb/include/lldb/lldb-enumerations.h (+1)
  • (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+3)
diff --git a/clang-tools-extra/clangd/DumpAST.cpp b/clang-tools-extra/clangd/DumpAST.cpp
index b0cec65c39fa31..9a525efb938e8d 100644
--- a/clang-tools-extra/clangd/DumpAST.cpp
+++ b/clang-tools-extra/clangd/DumpAST.cpp
@@ -143,6 +143,7 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
       TEMPLATE_ARGUMENT_KIND(Declaration);
       TEMPLATE_ARGUMENT_KIND(Template);
       TEMPLATE_ARGUMENT_KIND(TemplateExpansion);
+      TEMPLATE_ARGUMENT_KIND(StructuralValue);
 #undef TEMPLATE_ARGUMENT_KIND
     }
     llvm_unreachable("Unhandled ArgKind enum");
diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp
index 839cf6332fe8b0..a4a261030d399b 100644
--- a/clang-tools-extra/clangd/FindTarget.cpp
+++ b/clang-tools-extra/clangd/FindTarget.cpp
@@ -1032,6 +1032,7 @@ class ExplicitReferenceCollector
     case TemplateArgument::Pack:
     case TemplateArgument::Type:
     case TemplateArgument::Expression:
+    case TemplateArgument::StructuralValue:
       break; // Handled by VisitType and VisitExpression.
     };
     return RecursiveASTVisitor::TraverseTemplateArgumentLoc(A);
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 980be4fe0ef741..ac30805cf7f7b1 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -147,6 +147,8 @@ C++ Language Changes
 
 C++20 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
+- Implemented `P1907R1 <https://wg21.link/P1907R1>` which extends allowed non-type template argument
+  kinds with e.g. floating point values and pointers and references to subobjects.
 
 C++23 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/ODRHash.h b/clang/include/clang/AST/ODRHash.h
index cedf644520fc32..a1caa6d39a87c3 100644
--- a/clang/include/clang/AST/ODRHash.h
+++ b/clang/include/clang/AST/ODRHash.h
@@ -25,6 +25,7 @@
 
 namespace clang {
 
+class APValue;
 class Decl;
 class IdentifierInfo;
 class NestedNameSpecifier;
@@ -101,6 +102,8 @@ class ODRHash {
   // Save booleans until the end to lower the size of data to process.
   void AddBoolean(bool value);
 
+  void AddStructuralValue(const APValue &);
+
   static bool isSubDeclToBeProcessed(const Decl *D, const DeclContext *Parent);
 
 private:
diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td
index d86c4eba6a2251..0270c086d06b6a 100644
--- a/clang/include/clang/AST/PropertiesBase.td
+++ b/clang/include/clang/AST/PropertiesBase.td
@@ -808,6 +808,20 @@ let Class = PropertyTypeCase<TemplateArgument, "Integral"> in {
     return TemplateArgument(ctx, value, type, isDefaulted);
   }]>;
 }
+let Class = PropertyTypeCase<TemplateArgument, "StructuralValue"> in {
+  def : Property<"value", APValue> {
+    let Read = [{ node.getAsStructuralValue() }];
+  }
+  def : Property<"type", QualType> {
+    let Read = [{ node.getStructuralValueType() }];
+  }
+  def : Property<"isDefaulted", Bool> {
+    let Read = [{ node.getIsDefaulted() }];
+  }
+  def : Creator<[{
+    return TemplateArgument(ctx, type, value, isDefaulted);
+  }]>;
+}
 let Class = PropertyTypeCase<TemplateArgument, "Template"> in {
   def : Property<"name", TemplateName> {
     let Read = [{ node.getAsTemplateOrTemplatePattern() }];
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 8f2714e142bbe3..2aee6a947141b6 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -850,6 +850,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
   case TemplateArgument::Declaration:
   case TemplateArgument::Integral:
   case TemplateArgument::NullPtr:
+  case TemplateArgument::StructuralValue:
     return true;
 
   case TemplateArgument::Type:
@@ -882,6 +883,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
   case TemplateArgument::Declaration:
   case TemplateArgument::Integral:
   case TemplateArgument::NullPtr:
+  case TemplateArgument::StructuralValue:
     return true;
 
   case TemplateArgument::Type: {
diff --git a/clang/include/clang/AST/TemplateArgumentVisitor.h b/clang/include/clang/AST/TemplateArgumentVisitor.h
index 190aa97adf4551..cf0d3220158063 100644
--- a/clang/include/clang/AST/TemplateArgumentVisitor.h
+++ b/clang/include/clang/AST/TemplateArgumentVisitor.h
@@ -37,6 +37,7 @@ class Base {
       DISPATCH(Declaration);
       DISPATCH(NullPtr);
       DISPATCH(Integral);
+      DISPATCH(StructuralValue);
       DISPATCH(Template);
       DISPATCH(TemplateExpansion);
       DISPATCH(Expression);
@@ -59,6 +60,7 @@ class Base {
   VISIT_METHOD(Declaration);
   VISIT_METHOD(NullPtr);
   VISIT_METHOD(Integral);
+  VISIT_METHOD(StructuralValue);
   VISIT_METHOD(Template);
   VISIT_METHOD(TemplateExpansion);
   VISIT_METHOD(Expression);
diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h
index b7cd71f17c9442..42b267f67365c1 100644
--- a/clang/include/clang/AST/TemplateBase.h
+++ b/clang/include/clang/AST/TemplateBase.h
@@ -50,6 +50,7 @@ template <> struct PointerLikeTypeTraits<clang::Expr *> {
 
 namespace clang {
 
+class APValue;
 class ASTContext;
 class Expr;
 struct PrintingPolicy;
@@ -80,6 +81,13 @@ class TemplateArgument {
     /// that was provided for an integral non-type template parameter.
     Integral,
 
+    /// The template argument is a non-type template argument that can't be
+    /// represented by the special-case Declaration, NullPtr, or Integral
+    /// forms. These values are only ever produced by constant evaluation,
+    /// so cannot be dependent.
+    /// TODO: merge Declaration, NullPtr and Integral into this?
+    StructuralValue,
+
     /// The template argument is a template name that was provided for a
     /// template template parameter.
     Template,
@@ -130,6 +138,12 @@ class TemplateArgument {
     };
     void *Type;
   };
+  struct V {
+    unsigned Kind : 31;
+    unsigned IsDefaulted : 1;
+    APValue *Value;
+    void *Type;
+  };
   struct A {
     LLVM_PREFERRED_TYPE(ArgKind)
     unsigned Kind : 31;
@@ -156,11 +170,19 @@ class TemplateArgument {
   union {
     struct DA DeclArg;
     struct I Integer;
+    struct V Value;
     struct A Args;
     struct TA TemplateArg;
     struct TV TypeOrValue;
   };
 
+  void initFromType(QualType T, bool IsNullPtr, bool IsDefaulted);
+  void initFromDeclaration(ValueDecl *D, QualType QT, bool IsDefaulted);
+  void initFromIntegral(const ASTContext &Ctx, const llvm::APSInt &Value,
+                        QualType Type, bool IsDefaulted);
+  void initFromStructural(const ASTContext &Ctx, QualType Type,
+                          const APValue &V, bool IsDefaulted);
+
 public:
   /// Construct an empty, invalid template argument.
   constexpr TemplateArgument() : TypeOrValue({Null, 0, /* IsDefaulted */ 0}) {}
@@ -168,25 +190,22 @@ class TemplateArgument {
   /// Construct a template type argument.
   TemplateArgument(QualType T, bool isNullPtr = false,
                    bool IsDefaulted = false) {
-    TypeOrValue.Kind = isNullPtr ? NullPtr : Type;
-    TypeOrValue.IsDefaulted = IsDefaulted;
-    TypeOrValue.V = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+    initFromType(T, isNullPtr, IsDefaulted);
   }
 
-  /// Construct a template argument that refers to a
-  /// declaration, which is either an external declaration or a
-  /// template declaration.
+  /// Construct a template argument that refers to a (non-dependent)
+  /// declaration.
   TemplateArgument(ValueDecl *D, QualType QT, bool IsDefaulted = false) {
-    assert(D && "Expected decl");
-    DeclArg.Kind = Declaration;
-    DeclArg.IsDefaulted = IsDefaulted;
-    DeclArg.QT = QT.getAsOpaquePtr();
-    DeclArg.D = D;
+    initFromDeclaration(D, QT, IsDefaulted);
   }
 
   /// Construct an integral constant template argument. The memory to
   /// store the value is allocated with Ctx.
-  TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type,
+  TemplateArgument(const ASTContext &Ctx, const llvm::APSInt &Value,
+                   QualType Type, bool IsDefaulted = false);
+
+  /// Construct a template argument from an arbitrary constant value.
+  TemplateArgument(const ASTContext &Ctx, QualType Type, const APValue &Value,
                    bool IsDefaulted = false);
 
   /// Construct an integral constant template argument with the same
@@ -297,7 +316,7 @@ class TemplateArgument {
   /// Retrieve the type for a type template argument.
   QualType getAsType() const {
     assert(getKind() == Type && "Unexpected kind");
-    return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.V));
+    return QualType::getFromOpaquePtr(reinterpret_cast<void *>(TypeOrValue.V));
   }
 
   /// Retrieve the declaration for a declaration non-type
@@ -315,7 +334,7 @@ class TemplateArgument {
   /// Retrieve the type for null non-type template argument.
   QualType getNullPtrType() const {
     assert(getKind() == NullPtr && "Unexpected kind");
-    return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.V));
+    return QualType::getFromOpaquePtr(reinterpret_cast<void *>(TypeOrValue.V));
   }
 
   /// Retrieve the template name for a template name argument.
@@ -371,6 +390,14 @@ class TemplateArgument {
   /// default template parameter.
   bool getIsDefaulted() const { return (bool)TypeOrValue.IsDefaulted; }
 
+  /// Get the value of a StructuralValue.
+  const APValue &getAsStructuralValue() const { return *Value.Value; }
+
+  /// Get the type of a StructuralValue.
+  QualType getStructuralValueType() const {
+    return QualType::getFromOpaquePtr(Value.Type);
+  }
+
   /// If this is a non-type template argument, get its type. Otherwise,
   /// returns a null QualType.
   QualType getNonTypeTemplateArgumentType() const;
@@ -516,6 +543,7 @@ class TemplateArgumentLoc {
     assert(Argument.getKind() == TemplateArgument::NullPtr ||
            Argument.getKind() == TemplateArgument::Integral ||
            Argument.getKind() == TemplateArgument::Declaration ||
+           Argument.getKind() == TemplateArgument::StructuralValue ||
            Argument.getKind() == TemplateArgument::Expression);
   }
 
@@ -541,13 +569,9 @@ class TemplateArgumentLoc {
   /// - Fetches the full source range of the argument.
   SourceRange getSourceRange() const LLVM_READONLY;
 
-  const TemplateArgument &getArgument() const {
-    return Argument;
-  }
+  const TemplateArgument &getArgument() const { return Argument; }
 
-  TemplateArgumentLocInfo getLocInfo() const {
-    return LocInfo;
-  }
+  TemplateArgumentLocInfo getLocInfo() const { return LocInfo; }
 
   TypeSourceInfo *getTypeSourceInfo() const {
     if (Argument.getKind() != TemplateArgument::Type)
@@ -575,6 +599,11 @@ class TemplateArgumentLoc {
     return LocInfo.getAsExpr();
   }
 
+  Expr *getSourceStructuralValueExpression() const {
+    assert(Argument.getKind() == TemplateArgument::StructuralValue);
+    return LocInfo.getAsExpr();
+  }
+
   NestedNameSpecifierLoc getTemplateQualifierLoc() const {
     if (Argument.getKind() != TemplateArgument::Template &&
         Argument.getKind() != TemplateArgument::TemplateExpansion)
@@ -606,8 +635,7 @@ class TemplateArgumentListInfo {
 public:
   TemplateArgumentListInfo() = default;
 
-  TemplateArgumentListInfo(SourceLocation LAngleLoc,
-                           SourceLocation RAngleLoc)
+  TemplateArgumentListInfo(SourceLocation LAngleLoc, SourceLocation RAngleLoc)
       : LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {}
 
   // This can leak if used in an AST node, use ASTTemplateArgumentListInfo
@@ -626,21 +654,15 @@ class TemplateArgumentListInfo {
     return Arguments.data();
   }
 
-  llvm::ArrayRef<TemplateArgumentLoc> arguments() const {
-    return Arguments;
-  }
+  llvm::ArrayRef<TemplateArgumentLoc> arguments() const { return Arguments; }
 
   const TemplateArgumentLoc &operator[](unsigned I) const {
     return Arguments[I];
   }
 
-  TemplateArgumentLoc &operator[](unsigned I) {
-    return Arguments[I];
-  }
+  TemplateArgumentLoc &operator[](unsigned I) { return Arguments[I]; }
 
-  void addArgument(const TemplateArgumentLoc &Loc) {
-    Arguments.push_back(Loc);
-  }
+  void addArgument(const TemplateArgumentLoc &Loc) { Arguments.push_back(Loc); }
 };
 
 /// Represents an explicit template argument list in C++, e.g.,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a97182cad5d513..8f183158f7b3bb 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2253,6 +2253,8 @@ def warn_cxx17_compat_aggregate_init_paren_list : Warning<
 def err_reference_bind_to_bitfield : Error<
   "%select{non-const|volatile}0 reference cannot bind to "
   "bit-field%select{| %1}2">;
+def err_reference_bind_to_bitfield_in_cce : Error<
+  "reference cannot bind to bit-field in converted constant expression">;
 def err_reference_bind_to_vector_element : Error<
   "%select{non-const|volatile}0 reference cannot bind to vector element">;
 def err_reference_bind_to_matrix_element : Error<
@@ -5136,8 +5138,6 @@ def err_non_type_template_arg_subobject : Error<
   "non-type template argument refers to subobject '%0'">;
 def err_non_type_template_arg_addr_label_diff : Error<
   "template argument / label address difference / what did you expect?">;
-def err_non_type_template_arg_unsupported : Error<
-  "sorry, non-type template argument of type %0 is not yet supported">;
 def err_template_arg_not_convertible : Error<
   "non-type template argument of type %0 cannot be converted to a value "
   "of type %1">;
@@ -5189,9 +5189,6 @@ def err_template_arg_not_object_or_func : Error<
   "non-type template argument does not refer to an object or function">;
 def err_template_arg_not_pointer_to_member_form : Error<
   "non-type template argument is not a pointer to member constant">;
-def err_template_arg_member_ptr_base_derived_not_supported : Error<
-  "sorry, non-type template argument of pointer-to-member type %1 that refers "
-  "to member %q0 of a different class is not supported yet">;
 def err_template_arg_invalid : Error<
   "non-type template argument '%0' is invalid">;
 def ext_template_arg_extra_parens : ExtWarn<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4c464a1ae4c67f..6b0a9513f0e983 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8566,8 +8566,8 @@ class Sema final {
                                           QualType ParamType,
                                           SourceLocation Loc);
   ExprResult
-  BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
-                                              SourceLocation Loc);
+  BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg,
+                                             SourceLocation Loc);
 
   /// Enumeration describing how template parameter lists are compared
   /// for equality.
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index b60dcfaabfd1a4..b786ec8a0a3293 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -6746,6 +6746,11 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
     case TemplateArgument::Integral:
       return TemplateArgument(Arg, getCanonicalType(Arg.getIntegralType()));
 
+    case TemplateArgument::StructuralValue:
+      return TemplateArgument(*this,
+                              getCanonicalType(Arg.getStructuralValueType()),
+                              Arg.getAsStructuralValue());
+
     case TemplateArgument::Type:
       return TemplateArgument(getCanonicalType(Arg.getAsType()),
                               /*isNullPtr*/ false, Arg.getIsDefaulted());
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 5e5570bb42a1ef..491c2bbd148383 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -823,6 +823,17 @@ ASTNodeImporter::import(const TemplateArgument &From) {
                             From.getIsDefaulted());
   }
 
+  case TemplateArgument::StructuralValue: {
+    ExpectedType ToTypeOrErr = import(From.getStructuralValueType());
+    if (!ToTypeOrErr)
+      return ToTypeOrErr.takeError();
+    Expected<APValue> ToValueOrErr = import(From.getAsStructuralValue());
+    if (!ToValueOrErr)
+      return ToValueOrErr.takeError();
+    return TemplateArgument(Importer.getToContext(), *ToTypeOrErr,
+                            *ToValueOrErr);
+  }
+
   case TemplateArgument::Template: {
     Expected<TemplateName> ToTemplateOrErr = import(From.getAsTemplate());
     if (!ToTemplateOrErr)
@@ -3572,6 +3583,8 @@ class IsTypeDeclaredInsideVisitor
     case TemplateArgument::NullPtr:
       // FIXME: The type is not allowed to be in the function?
       return CheckType(Arg.getNullPtrType());
+    case TemplateArgument::StructuralValue:
+      return CheckType(Arg.getStructuralValueType());
     case TemplateArgument::Pack:
       for (const auto &PackArg : Arg.getPackAsArray())
         if (checkTemplateArgument(PackArg))
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index a9e0d1698a9178..39a2f7ce61e135 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -628,6 +628,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
     return IsStructurallyEquivalent(Context, Arg1.getAsExpr(),
                                     Arg2.getAsExpr());
 
+  case TemplateArgument::StructuralValue:
+    // FIXME: Do we need to customize the comparison?
+    return Arg1.structurallyEquals(Arg2);
+
   case TemplateArgument::Pack:
     return IsStructurallyEquivalent(Context, Arg1.pack_elements(),
                                     Arg2.pack_elements());
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index e1440e5183a4e6..a2f50ae4ce8eeb 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -343,6 +343,10 @@ LinkageComputer::getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
       LV.merge(getTypeLinkageAndVisibility(Arg.getNullPtrType()));
       continue;
 
+    case TemplateArgument::StructuralValue:
+      LV.merge(getLVForValue(Arg.getAsStructuralValue(), computation));
+      continue;
+
     case TemplateArgument::Template:
     case TemplateArgument::TemplateExpansion:
       if (TemplateDecl *Template =
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index b1678479888eb7..d3ef822b371d5e 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -4833,9 +4833,26 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
     E = cast<CXXStdInitializerListExpr>(E)->getSubExpr();
     goto recurse;
 
-  case Expr::SubstNonTypeTemplateParmExprClass:
+  case Expr::SubstNonTypeTemplateParmExprClass: {
+    // Mangle a substituted parameter the same way we mangle the template
+    // argument.
+    auto *SNTTPE = cast<SubstNonTypeTemplateParmExpr>(E);
+    if (auto *CE = dyn_cast<ConstantExpr>(SNTTPE->getReplacement())) {
+      // Pull out the constant value and mangle it as a template argument.
+      QualType ParamType = SNTTPE->getParameterType(Context.getASTContext());
+      if (CE->hasAPValueResult())
+        mangleValueInTemplateArg(ParamType, CE->getResultAsAPValue(), false,
+                                 /*NeedExactType=*/true);
+      else
+        mangleValueInTemplateArg(ParamType, CE->getAPValueResult(), false,
+                                 /*NeedExactType=*/true);
+      break;
+    }
+    // The remaining cases all happen to be substituted with expressions that
+    // mangle the same as a corresponding template argument anyway.
     E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
     goto recurse;
+  }
 
   case Expr::UserDefinedLiteralClass:
     // We follow g++'s approach of mangling a UDL as a call to the literal
@@ -6064,6 +6081,11 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) {
     mangleNullPointer(A.getNullPtrType());
     break;
   }
+  case TemplateArgument::StructuralValue:
+    mangleValueInTemplateArg(A.getStructuralValueType(),
+                             A.getAsStructu...
[truncated]

@bolshakov-a
Copy link
Contributor

@cor3ntin, thank you! Could you please take a look and probably merge #71077? This depends on that PR.

@bolshakov-a
Copy link
Contributor

Have I understood correctly that I should open my own PR to proceed working on this?

@cor3ntin
Copy link
Contributor Author

cor3ntin commented Jan 9, 2024 via email

@bolshakov-a
Copy link
Contributor

Seems like I should ping reviewers more actively... Ok, thanks, I'll probably proceed at the weekend.

@cor3ntin
Copy link
Contributor Author

@bolshakov-a we are going to branch LLVM 23 in about 10 days. If you can update this by early next week, we will try to finish the review so that it can land in 18.

@bolshakov-a
Copy link
Contributor

@cor3ntin, #78041.

@cor3ntin
Copy link
Contributor Author

Author opened #78041 - closing

@cor3ntin cor3ntin closed this Jan 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category clangd debuginfo lldb
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants