https://github.com/tynasello updated 
https://github.com/llvm/llvm-project/pull/151400

>From e7c6ad6a7642c90414da78073c29695fe5ea036f Mon Sep 17 00:00:00 2001
From: tynasello <tynase...@gmail.com>
Date: Tue, 29 Jul 2025 23:41:09 +0000
Subject: [PATCH 1/2] [Clang] Add template argument support for
 {con,de}structor attributes.

Fixes: https://github.com/llvm/llvm-project/issues/67154
---
 clang/include/clang/Basic/Attr.td             | 12 +++++-
 clang/lib/CodeGen/CodeGenModule.cpp           | 14 ++++++-
 clang/lib/Sema/SemaDeclAttr.cpp               | 39 +++++++++++++------
 clang/test/AST/ast-dump-attr.cpp              |  3 +-
 clang/test/CodeGenCXX/constructor-attr.cpp    | 15 +++++++
 clang/test/CodeGenCXX/destructor-attr.cpp     | 23 +++++++++++
 ...-attribute.c => constructor-attribute.cpp} |  4 +-
 7 files changed, 92 insertions(+), 18 deletions(-)
 create mode 100644 clang/test/CodeGenCXX/destructor-attr.cpp
 rename clang/test/Sema/{constructor-attribute.c => constructor-attribute.cpp} 
(77%)

diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index 224cb6a32af28..c67aaeda9be70 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1463,9 +1463,13 @@ def ConstInit : InheritableAttr {
 
 def Constructor : InheritableAttr {
   let Spellings = [GCC<"constructor">];
-  let Args = [DefaultIntArgument<"Priority", 65535>];
+  let Args = [ExprArgument<"Priority", 1>];
   let Subjects = SubjectList<[Function]>;
+  let TemplateDependent = 1;
   let Documentation = [CtorDtorDocs];
+  let AdditionalMembers = [{
+    static constexpr unsigned int DefaultPriority = 65535; 
+  }];
 }
 
 def CPUSpecific : InheritableAttr {
@@ -1797,9 +1801,13 @@ def Deprecated : InheritableAttr {
 
 def Destructor : InheritableAttr {
   let Spellings = [GCC<"destructor">];
-  let Args = [DefaultIntArgument<"Priority", 65535>];
+  let Args = [ExprArgument<"Priority", 1>];
   let Subjects = SubjectList<[Function]>;
+  let TemplateDependent = 1;
   let Documentation = [CtorDtorDocs];
+  let AdditionalMembers = [{
+    static constexpr unsigned int DefaultPriority = 65535; 
+  }];
 }
 
 def EmptyBases : InheritableAttr, 
TargetSpecificAttr<TargetMicrosoftRecordLayout> {
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index 834b1c067d84c..1bd6998ca3c75 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -6324,10 +6324,20 @@ void 
CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
 
   SetLLVMFunctionAttributesForDefinition(D, Fn);
 
+  auto getPriority = [this](auto *Attr) -> int {
+    int priority = Attr->DefaultPriority;
+    Expr *E = Attr->getPriority();
+    if (E) {
+      if (auto CE = E->getIntegerConstantExpr(this->getContext()))
+        priority = CE->getExtValue();
+    }
+    return priority;
+  };
+
   if (const ConstructorAttr *CA = D->getAttr<ConstructorAttr>())
-    AddGlobalCtor(Fn, CA->getPriority());
+    AddGlobalCtor(Fn, getPriority(CA));
   if (const DestructorAttr *DA = D->getAttr<DestructorAttr>())
-    AddGlobalDtor(Fn, DA->getPriority(), true);
+    AddGlobalDtor(Fn, getPriority(DA), true);
   if (getLangOpts().OpenMP && D->hasAttr<OMPDeclareTargetDeclAttr>())
     getOpenMPRuntime().emitDeclareTargetFunction(D, GV);
 }
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 16b18bcb6a2a0..e03ba4c49e328 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -2152,29 +2152,44 @@ static void handleUnusedAttr(Sema &S, Decl *D, const 
ParsedAttr &AL) {
   D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
 }
 
+static std::optional<Expr *> sharedGetConstructorDestructorAttrExpr(Sema &S, 
const ParsedAttr &AL) {
+  Expr *E = nullptr;
+  if (AL.getNumArgs() == 1) {
+    E = AL.getArgAsExpr(0);
+    if (E->isValueDependent()) {
+      if (!E->isTypeDependent() && !E->getType()->isIntegerType()) {
+        S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+            << AL << AANT_ArgumentIntegerConstant << E->getSourceRange();
+        return std::nullopt;
+      }
+    } else {
+      uint32_t priority;
+      if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) {
+        return std::nullopt;
+      }
+    }
+  } 
+  return E;
+}
+
 static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
-  uint32_t priority = ConstructorAttr::DefaultPriority;
   if (S.getLangOpts().HLSL && AL.getNumArgs()) {
     S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported);
     return;
   }
-  if (AL.getNumArgs() &&
-      !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority))
+  auto E = sharedGetConstructorDestructorAttrExpr(S, AL);
+  if (!E.has_value())
     return;
-  S.Diag(D->getLocation(), diag::warn_global_constructor)
-      << D->getSourceRange();
-
-  D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority));
+  S.Diag(D->getLocation(), diag::warn_global_constructor) << 
D->getSourceRange();
+  D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, E.value()));
 }
 
 static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
-  uint32_t priority = DestructorAttr::DefaultPriority;
-  if (AL.getNumArgs() &&
-      !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority))
+  auto E = sharedGetConstructorDestructorAttrExpr(S, AL);
+  if (!E.has_value())
     return;
   S.Diag(D->getLocation(), diag::warn_global_destructor) << 
D->getSourceRange();
-
-  D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority));
+  D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, E.value()));
 }
 
 template <typename AttrTy>
diff --git a/clang/test/AST/ast-dump-attr.cpp b/clang/test/AST/ast-dump-attr.cpp
index f5a7481571421..a824724abc773 100644
--- a/clang/test/AST/ast-dump-attr.cpp
+++ b/clang/test/AST/ast-dump-attr.cpp
@@ -88,7 +88,8 @@ __attribute__((pointer_with_type_tag(unsigned1,1,2)));
 
 void TestInt(void) __attribute__((constructor(123)));
 // CHECK:      FunctionDecl{{.*}}TestInt
-// CHECK-NEXT:   ConstructorAttr{{.*}} 123
+// CHECK-NEXT:   ConstructorAttr
+// CHECK-NEXT:   IntegerLiteral{{.*}} 123
 
 static int TestString __attribute__((alias("alias1")));
 // CHECK:      VarDecl{{.*}}TestString
diff --git a/clang/test/CodeGenCXX/constructor-attr.cpp 
b/clang/test/CodeGenCXX/constructor-attr.cpp
index ec27ed210ce76..5959d824f78c8 100644
--- a/clang/test/CodeGenCXX/constructor-attr.cpp
+++ b/clang/test/CodeGenCXX/constructor-attr.cpp
@@ -1,6 +1,10 @@
 // RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck 
%s
 
 // CHECK: @llvm.global_ctors
+// CHECK-SAME: i32 65535, ptr @_ZN3Foo3fooEv
+// CHECK-SAME: i32 101, ptr @_Z22template_dependent_cxxILi101EEvv
+// CHECK-SAME: i32 102, ptr @_Z22template_dependent_gnuILi102EEvv
+// CHECK-SAME: i32 104, ptr @_Z23template_dependent_nttpIiLi104EEvv
 
 // PR6521
 void bar();
@@ -10,3 +14,14 @@ struct Foo {
     bar();
   }
 };
+
+template <int P>
+[[gnu::constructor(P)]] void template_dependent_cxx() {}
+template <int P>
+__attribute__((constructor(P))) void template_dependent_gnu() {}
+template <typename T, int P = sizeof(T) * 26>
+[[gnu::constructor(P)]] void template_dependent_nttp() {}
+
+template void template_dependent_cxx<101>();
+template void template_dependent_gnu<102>();
+template void template_dependent_nttp<int>();
diff --git a/clang/test/CodeGenCXX/destructor-attr.cpp 
b/clang/test/CodeGenCXX/destructor-attr.cpp
new file mode 100644
index 0000000000000..f0500caed3ccd
--- /dev/null
+++ b/clang/test/CodeGenCXX/destructor-attr.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck 
%s
+
+// CHECK: @llvm.global_dtors
+// CHECK-SAME: i32 65535, ptr @_ZN3Foo3fooEv
+// CHECK-SAME: i32 101, ptr @_Z22template_dependent_cxxILi101EEvv
+// CHECK-SAME: i32 104, ptr @_Z23template_dependent_nttpIiLi104EEvv
+
+// PR6521
+void bar();
+struct Foo {
+  // CHECK-LABEL: define linkonce_odr {{.*}}void @_ZN3Foo3fooEv
+  static void foo() __attribute__((destructor)) {
+    bar();
+  }
+};
+
+template <int P>
+[[gnu::destructor(P)]] void template_dependent_cxx() {}
+template <typename T, int P = sizeof(T) * 26>
+[[gnu::destructor(P)]] void template_dependent_nttp() {}
+
+template void template_dependent_cxx<101>();
+template void template_dependent_nttp<int>();
diff --git a/clang/test/Sema/constructor-attribute.c 
b/clang/test/Sema/constructor-attribute.cpp
similarity index 77%
rename from clang/test/Sema/constructor-attribute.c
rename to clang/test/Sema/constructor-attribute.cpp
index 2317c7735bda5..6ebb3d6be8a3f 100644
--- a/clang/test/Sema/constructor-attribute.c
+++ b/clang/test/Sema/constructor-attribute.cpp
@@ -6,11 +6,13 @@ int f(void) __attribute__((constructor(1)));
 int f(void) __attribute__((constructor(1,2))); // expected-error 
{{'constructor' attribute takes no more than 1 argument}}
 int f(void) __attribute__((constructor(1.0))); // expected-error 
{{'constructor' attribute requires an integer constant}}
 int f(void) __attribute__((constructor(0x100000000))); // expected-error 
{{integer constant expression evaluates to value 4294967296 that cannot be 
represented in a 32-bit unsigned integer type}}
+template <int *I> [[gnu::constructor(I)]] void f(); // expected-error 
{{'gnu::constructor' attribute requires an integer constant}}
 
-int x __attribute__((destructor)); // expected-warning {{'destructor' 
attribute only applies to functions}}
+int y __attribute__((destructor)); // expected-warning {{'destructor' 
attribute only applies to functions}}
 int f(void) __attribute__((destructor));
 int f(void) __attribute__((destructor(1)));
 int f(void) __attribute__((destructor(1,2))); // expected-error {{'destructor' 
attribute takes no more than 1 argument}}
 int f(void) __attribute__((destructor(1.0))); // expected-error {{'destructor' 
attribute requires an integer constant}}
+template <int *I> [[gnu::destructor(I)]] void f(); // expected-error 
{{'gnu::destructor' attribute requires an integer constant}}
 
 void knr() __attribute__((constructor));

>From d3a1e1f38b8f84a437da5e0b22eb5e776bef0f94 Mon Sep 17 00:00:00 2001
From: tynasello <tynase...@gmail.com>
Date: Thu, 14 Aug 2025 18:08:35 +0000
Subject: [PATCH 2/2] [Clang] Add template argument support for
 {con,de}structor attributes.

Address PR comments.
---
 clang/include/clang/Basic/Attr.td             |  2 +-
 clang/lib/CodeGen/CodeGenModule.cpp           | 12 ++---
 clang/lib/Sema/SemaDeclAttr.cpp               | 15 ++++--
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 39 +++++++++++++++
 clang/test/CodeGenCXX/constructor-attr.cpp    |  3 ++
 clang/test/Sema/constructor-attribute.cpp     | 50 +++++++++++++++++--
 6 files changed, 107 insertions(+), 14 deletions(-)

diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index c67aaeda9be70..308fd3d251116 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1468,7 +1468,7 @@ def Constructor : InheritableAttr {
   let TemplateDependent = 1;
   let Documentation = [CtorDtorDocs];
   let AdditionalMembers = [{
-    static constexpr unsigned int DefaultPriority = 65535; 
+    static constexpr unsigned DefaultPriority = 65535; 
   }];
 }
 
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index 1bd6998ca3c75..fbf70217ffdd0 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -6324,20 +6324,18 @@ void 
CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
 
   SetLLVMFunctionAttributesForDefinition(D, Fn);
 
-  auto getPriority = [this](auto *Attr) -> int {
-    int priority = Attr->DefaultPriority;
+  auto GetPriority = [this](const auto *Attr) -> int {
     Expr *E = Attr->getPriority();
     if (E) {
-      if (auto CE = E->getIntegerConstantExpr(this->getContext()))
-        priority = CE->getExtValue();
+      return E->EvaluateKnownConstInt(this->getContext()).getExtValue();
     }
-    return priority;
+    return Attr->DefaultPriority;
   };
 
   if (const ConstructorAttr *CA = D->getAttr<ConstructorAttr>())
-    AddGlobalCtor(Fn, getPriority(CA));
+    AddGlobalCtor(Fn, GetPriority(CA));
   if (const DestructorAttr *DA = D->getAttr<DestructorAttr>())
-    AddGlobalDtor(Fn, getPriority(DA), true);
+    AddGlobalDtor(Fn, GetPriority(DA), true);
   if (getLangOpts().OpenMP && D->hasAttr<OMPDeclareTargetDeclAttr>())
     getOpenMPRuntime().emitDeclareTargetFunction(D, GV);
 }
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index e03ba4c49e328..2d2ca85f2f9a2 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -10,6 +10,7 @@
 //
 
//===----------------------------------------------------------------------===//
 
+#include "clang/AST/APValue.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTMutationListener.h"
@@ -58,6 +59,7 @@
 #include "clang/Sema/SemaSwift.h"
 #include "clang/Sema/SemaWasm.h"
 #include "clang/Sema/SemaX86.h"
+#include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Demangle/Demangle.h"
@@ -2152,7 +2154,11 @@ static void handleUnusedAttr(Sema &S, Decl *D, const 
ParsedAttr &AL) {
   D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
 }
 
-static std::optional<Expr *> sharedGetConstructorDestructorAttrExpr(Sema &S, 
const ParsedAttr &AL) {
+static std::optional<Expr *>
+sharedGetConstructorDestructorAttrExpr(Sema &S, const ParsedAttr &AL) {
+  // If no Expr node exists on the attribute, return a nullptr (default 
priority
+  // to be used). If Expr node exists but is not valid, return a nullopt.
+  // Otherwise, return the Expr.
   Expr *E = nullptr;
   if (AL.getNumArgs() == 1) {
     E = AL.getArgAsExpr(0);
@@ -2167,8 +2173,10 @@ static std::optional<Expr *> 
sharedGetConstructorDestructorAttrExpr(Sema &S, con
       if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) {
         return std::nullopt;
       }
+      return ConstantExpr::Create(S.Context, E,
+                                  
APValue(llvm::APSInt::getUnsigned(priority)));
     }
-  } 
+  }
   return E;
 }
 
@@ -2180,7 +2188,8 @@ static void handleConstructorAttr(Sema &S, Decl *D, const 
ParsedAttr &AL) {
   auto E = sharedGetConstructorDestructorAttrExpr(S, AL);
   if (!E.has_value())
     return;
-  S.Diag(D->getLocation(), diag::warn_global_constructor) << 
D->getSourceRange();
+  S.Diag(D->getLocation(), diag::warn_global_constructor)
+      << D->getSourceRange();
   D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, E.value()));
 }
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 233bb659d37fd..71ada6d6891f1 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -233,6 +233,33 @@ static void instantiateDependentAnnotationAttr(
   }
 }
 
+template <typename Attr>
+static void sharedInstantiateConstructorDestructorAttr(
+    Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const Attr *A,
+    Decl *New, ASTContext &C) {
+  Expr *tempInstPriority = nullptr;
+  {
+    EnterExpressionEvaluationContext Unevaluated(
+        S, Sema::ExpressionEvaluationContext::Unevaluated);
+    ExprResult Result = S.SubstExpr(A->getPriority(), TemplateArgs);
+    if (Result.isInvalid())
+      return;
+    tempInstPriority = Result.get();
+    if (auto CE = tempInstPriority->getIntegerConstantExpr(C)) {
+      // Consistent with non-templated priority arguments, which must fit in a
+      // 32-bit unsigned integer.
+      if (!CE->isIntN(32)) {
+        S.Diag(tempInstPriority->getExprLoc(), diag::err_ice_too_large)
+            << toString(*CE, 10, false) << 32 << 1;
+        return;
+      }
+    }
+  }
+  Attr *NewAttr = new (C) Attr(C, *A, tempInstPriority);
+  if (NewAttr)
+    New->addAttr(NewAttr);
+}
+
 static Expr *instantiateDependentFunctionAttrCondition(
     Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
     const Attr *A, Expr *OldCond, const Decl *Tmpl, FunctionDecl *New) {
@@ -824,6 +851,18 @@ void Sema::InstantiateAttrs(const 
MultiLevelTemplateArgumentList &TemplateArgs,
       continue;
     }
 
+    if (auto *Constructor = dyn_cast<ConstructorAttr>(TmplAttr)) {
+      sharedInstantiateConstructorDestructorAttr(*this, TemplateArgs,
+                                                 Constructor, New, Context);
+      continue;
+    }
+
+    if (auto *Destructor = dyn_cast<DestructorAttr>(TmplAttr)) {
+      sharedInstantiateConstructorDestructorAttr(*this, TemplateArgs,
+                                                 Destructor, New, Context);
+      continue;
+    }
+
     if (const auto *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr)) {
       instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl,
                                        cast<FunctionDecl>(New));
diff --git a/clang/test/CodeGenCXX/constructor-attr.cpp 
b/clang/test/CodeGenCXX/constructor-attr.cpp
index 5959d824f78c8..d73b661f1ec40 100644
--- a/clang/test/CodeGenCXX/constructor-attr.cpp
+++ b/clang/test/CodeGenCXX/constructor-attr.cpp
@@ -4,6 +4,7 @@
 // CHECK-SAME: i32 65535, ptr @_ZN3Foo3fooEv
 // CHECK-SAME: i32 101, ptr @_Z22template_dependent_cxxILi101EEvv
 // CHECK-SAME: i32 102, ptr @_Z22template_dependent_gnuILi102EEvv
+// CHECK-SAME: i32 103, ptr @_Z1fv
 // CHECK-SAME: i32 104, ptr @_Z23template_dependent_nttpIiLi104EEvv
 
 // PR6521
@@ -15,6 +16,7 @@ struct Foo {
   }
 };
 
+
 template <int P>
 [[gnu::constructor(P)]] void template_dependent_cxx() {}
 template <int P>
@@ -24,4 +26,5 @@ template <typename T, int P = sizeof(T) * 26>
 
 template void template_dependent_cxx<101>();
 template void template_dependent_gnu<102>();
+[[gnu::constructor(103)]] void f() {}
 template void template_dependent_nttp<int>();
diff --git a/clang/test/Sema/constructor-attribute.cpp 
b/clang/test/Sema/constructor-attribute.cpp
index 6ebb3d6be8a3f..159d495f64691 100644
--- a/clang/test/Sema/constructor-attribute.cpp
+++ b/clang/test/Sema/constructor-attribute.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -Wno-strict-prototypes %s
+// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wno-strict-prototypes %s
 
 int x __attribute__((constructor)); // expected-warning {{'constructor' 
attribute only applies to functions}}
 int f(void) __attribute__((constructor));
@@ -6,13 +7,56 @@ int f(void) __attribute__((constructor(1)));
 int f(void) __attribute__((constructor(1,2))); // expected-error 
{{'constructor' attribute takes no more than 1 argument}}
 int f(void) __attribute__((constructor(1.0))); // expected-error 
{{'constructor' attribute requires an integer constant}}
 int f(void) __attribute__((constructor(0x100000000))); // expected-error 
{{integer constant expression evaluates to value 4294967296 that cannot be 
represented in a 32-bit unsigned integer type}}
-template <int *I> [[gnu::constructor(I)]] void f(); // expected-error 
{{'gnu::constructor' attribute requires an integer constant}}
+void knr() __attribute__((constructor));
+
+#ifdef __cplusplus
+template <int *P> 
+[[gnu::constructor(P)]] void f(); // expected-error {{'gnu::constructor' 
attribute requires an integer constant}}
+
+template <long long P> 
+[[gnu::constructor(P)]] void f() {} // expected-error {{integer constant 
expression evaluates to value 4294967296 that cannot be represented in a 32-bit 
unsigned integer type}} 
+template void f<1LL<<32>(); // expected-note {{in instantiation of function 
template specialization 'f<4294967296LL>' requested here}}
+template void f<101>();
+
+template <typename T>
+[[gnu::constructor(static_cast<T>(101))]] void f() {}
+template void f<int>();
+template void f<long long>();
+
+template <typename T>
+[[gnu::constructor(static_cast<T>(1LL<<32))]] void g() {}
+template void g<int>();
+
+template <typename T>
+[[gnu::constructor(static_cast<T>(1LL<<32))]] void h() {} // expected-error 
{{integer constant expression evaluates to value 4294967296 that cannot be 
represented in a 32-bit unsigned integer type}} 
+template void h<long long>(); // expected-note {{in instantiation of function 
template specialization 'h<long long>' requested here}}
+#endif
 
 int y __attribute__((destructor)); // expected-warning {{'destructor' 
attribute only applies to functions}}
 int f(void) __attribute__((destructor));
 int f(void) __attribute__((destructor(1)));
 int f(void) __attribute__((destructor(1,2))); // expected-error {{'destructor' 
attribute takes no more than 1 argument}}
 int f(void) __attribute__((destructor(1.0))); // expected-error {{'destructor' 
attribute requires an integer constant}}
-template <int *I> [[gnu::destructor(I)]] void f(); // expected-error 
{{'gnu::destructor' attribute requires an integer constant}}
 
-void knr() __attribute__((constructor));
+#ifdef __cplusplus
+template <int *I> 
+[[gnu::destructor(I)]] void f(); // expected-error {{'gnu::destructor' 
attribute requires an integer constant}}
+
+template <long long P> 
+[[gnu::destructor(P)]] void fd() {} // expected-error {{integer constant 
expression evaluates to value 4294967296 that cannot be represented in a 32-bit 
unsigned integer type}} 
+template void fd<1LL<<32>(); // expected-note {{in instantiation of function 
template specialization 'fd<4294967296LL>' requested here}}
+template void fd<101>();
+
+template <typename T>
+[[gnu::destructor(static_cast<T>(101))]] void fd() {}
+template void fd<int>();
+template void fd<long long>();
+
+template <typename T>
+[[gnu::destructor(static_cast<T>(1LL<<32))]] void gd() {}
+template void gd<int>();
+
+template <typename T>
+[[gnu::destructor(static_cast<T>(1LL<<32))]] void hd() {} // expected-error 
{{integer constant expression evaluates to value 4294967296 that cannot be 
represented in a 32-bit unsigned integer type}} 
+template void hd<long long>(); // expected-note {{in instantiation of function 
template specialization 'hd<long long>' requested here}}
+#endif

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to