[Clang] perform "maximum TLS alignment" check for template instantiation
authorYuanfang Chen <yuanfang.chen@sony.com>
Mon, 31 Oct 2022 04:33:10 +0000 (21:33 -0700)
committerYuanfang Chen <yuanfang.chen@sony.com>
Mon, 31 Oct 2022 05:39:47 +0000 (22:39 -0700)
follow up https://github.com/llvm/llvm-project/commit/d30e2eefc3cf8dfd2210aefd62f13a6e7c011b43

Reviewed By: mizvekov

Differential Revision: https://reviews.llvm.org/D136744

clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/Sema/tls_alignment.cpp

index b32dfe1..23b4e3f 100644 (file)
@@ -3013,6 +3013,7 @@ public:
   void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc);
   void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc);
   void CheckStaticLocalForDllExport(VarDecl *VD);
+  void CheckThreadLocalForLargeAlignment(VarDecl *VD);
   void FinalizeDeclaration(Decl *D);
   DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
                                          ArrayRef<Decl *> Group);
index 19bd670..686a126 100644 (file)
@@ -14032,6 +14032,26 @@ void Sema::CheckStaticLocalForDllExport(VarDecl *VD) {
   }
 }
 
+void Sema::CheckThreadLocalForLargeAlignment(VarDecl *VD) {
+  assert(VD->getTLSKind());
+
+  // Perform TLS alignment check here after attributes attached to the variable
+  // which may affect the alignment have been processed. Only perform the check
+  // if the target has a maximum TLS alignment (zero means no constraints).
+  if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) {
+    // Protect the check so that it's not performed on dependent types and
+    // dependent alignments (we can't determine the alignment in that case).
+    if (!VD->hasDependentAlignment()) {
+      CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign);
+      if (Context.getDeclAlign(VD) > MaxAlignChars) {
+        Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum)
+            << (unsigned)Context.getDeclAlign(VD).getQuantity() << VD
+            << (unsigned)MaxAlignChars.getQuantity();
+      }
+    }
+  }
+}
+
 /// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform
 /// any semantic actions necessary after any initializer has been attached.
 void Sema::FinalizeDeclaration(Decl *ThisDecl) {
@@ -14075,25 +14095,12 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) {
 
   checkAttributesAfterMerging(*this, *VD);
 
-  // Perform TLS alignment check here after attributes attached to the variable
-  // which may affect the alignment have been processed. Only perform the check
-  // if the target has a maximum TLS alignment (zero means no constraints).
-  if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) {
-    // Protect the check so that it's not performed on dependent types and
-    // dependent alignments (we can't determine the alignment in that case).
-    if (VD->getTLSKind() && !VD->hasDependentAlignment()) {
-      CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign);
-      if (Context.getDeclAlign(VD) > MaxAlignChars) {
-        Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum)
-          << (unsigned)Context.getDeclAlign(VD).getQuantity() << VD
-          << (unsigned)MaxAlignChars.getQuantity();
-      }
-    }
-  }
-
   if (VD->isStaticLocal())
     CheckStaticLocalForDllExport(VD);
 
+  if (VD->getTLSKind())
+    CheckThreadLocalForLargeAlignment(VD);
+
   // Perform check for initializers of device-side global variables.
   // CUDA allows empty constructors as initializers (see E.2.3.1, CUDA
   // 7.5). We must also apply the same checks to all __shared__
index d8dd1ab..da9aa61 100644 (file)
@@ -4341,7 +4341,7 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
   }
 
   const auto *VD = dyn_cast<VarDecl>(D);
-  if (VD && Context.getTargetInfo().isTLSSupported()) {
+  if (VD) {
     unsigned MaxTLSAlign =
         Context.toCharUnitsFromBits(Context.getTargetInfo().getMaxTLSAlign())
             .getQuantity();
index e034094..49be412 100644 (file)
@@ -1179,6 +1179,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
   if (Var->isStaticLocal())
     SemaRef.CheckStaticLocalForDllExport(Var);
 
+  if (Var->getTLSKind())
+    SemaRef.CheckThreadLocalForLargeAlignment(Var);
+
   return Var;
 }
 
index 18db565..c5c79aa 100644 (file)
@@ -58,27 +58,34 @@ int baz ()
            bar5.some_data[5];
 }
 
-
-// Verify alignment check where a dependent type is involved.
-// The check is (correctly) not performed on "t", but the check still is
-// performed on the structure as a whole once it has been instantiated.
-
 template<class T> struct templated_tls {
     static __thread T t;
     T other_t __attribute__(( aligned(64) ));
 };
-__thread templated_tls<int> blah; // expected-error{{alignment (64) of thread-local variable}}
-
-int blag() {
-    return blah.other_t * 2;
-}
+ __thread templated_tls<int> blah; // expected-error{{alignment (64) of thread-local variable}}
 
-
-// Verify alignment check where the alignment is a template parameter.
-// The check is only performed during instantiation.
 template <int N>
 struct S {
+  struct alignas(64) B {};
+  struct alignas(N) C {};
+  static inline void f() {
+    thread_local B b; // expected-error{{alignment (64) of thread-local variable}}
+    thread_local C c; // expected-error{{alignment (64) of thread-local variable}}
+  }
+  template<int J> static inline thread_local int b alignas(J) = J; // expected-error{{alignment (64) of thread-local variable}}
   static int __thread __attribute__((aligned(N))) x; // expected-error{{alignment (64) of thread-local variable}}
 };
 
-S<64> s_instance; // expected-note{{in instantiation of template class 'S<64>' requested here}}
+int blag() {
+    // Verify alignment check where the alignment is a template parameter.
+    // The check is only performed during instantiation.
+    S<64> s_instance; // expected-note{{in instantiation of template class 'S<64>' requested here}}
+
+    // Verify alignment for dependent local variables.
+    S<64>::f(); // expected-note{{in instantiation of member function 'S<64>::f' requested here}}
+
+    // Verify alignment check where a dependent type is involved.
+    // The check is (correctly) not performed on "t", but the check still is
+    // performed on the structure as a whole once it has been instantiated.
+    return blah.other_t * 2 + S<64>::b<64>; // expected-note{{in instantiation of static data member 'S<64>::b' requested here}}
+}