================
@@ -15460,6 +15462,126 @@ void Sema::CheckThreadLocalForLargeAlignment(VarDecl 
*VD) {
   }
 }
 
+/// Process a variable definition whose mangled name may be listed in
+/// '-mloadtime-comment-vars=': attach an implicit attribute to supported
+/// string variables so CodeGen preserves them as loadtime identifying
+/// strings, and warn when a named variable cannot be preserved.
+static void processForLoadTimeCommentVar(Sema &S, VarDecl *VD) {
+  if (S.getLangOpts().LoadTimeCommentVars.empty() || VD->isInvalidDecl())
+    return;
+
+  // Declarations that cannot be name-matched are silently skipped: an
+  // automatic variable has no symbol of its own, and neither does a template
+  // pattern (only its specializations do, and those are processed
+  // separately). Only definitions are considered.
+  if (VD->hasLocalStorage())
+    return;
+  if (VD->isTemplated())
+    return;
+  if (VD->isThisDeclarationADefinition(S.Context) != VarDecl::Definition)
+    return;
+
+  // A definition without an initializer carries no string and is silently
+  // skipped.
+  if (!VD->hasInit())
+    return;
+
+  // Extract the character type a pointer points to or an array holds; it is
+  // null for any other type, which is classified (and diagnosed) below once
+  // the name has matched.
+  QualType Ty = VD->getType();
+  const PointerType *PT = Ty->getAsCanonical<PointerType>();
+  const ArrayType *AT = PT ? nullptr : S.Context.getAsArrayType(Ty);
+  QualType Pointee = PT   ? PT->getPointeeType()
+                     : AT ? AT->getElementType()
+                          : QualType();
+
+  // Mangling is comparatively expensive, so first check cheaply whether the
+  // source identifier appears in any listed name at all: both the Itanium
+  // mangling and an unmangled C name embed the identifier verbatim. A
+  // declaration without an identifier (a structured binding) has no such
+  // shortcut and is mangled directly; nor does a variable with an assembler
+  // label, since the label replaces the identifier in the object-file name.
+  if (const IdentifierInfo *II = VD->getIdentifier()) {
+    if (!VD->hasAttr<AsmLabelAttr>()) {
+      StringRef Name = II->getName();
+      if (llvm::none_of(
+              S.getLangOpts().LoadTimeCommentVars,
+              [Name](StringRef Listed) { return Listed.contains(Name); }))
+        return;
+    }
+  }
+  // Names are matched against the mangled name, as it appears in the object
+  // file. For plain C file-scope variables this is the source identifier; for
+  // C++ variables it is the mangled symbol.
+  if (!S.LoadTimeCommentVarNameGenerator)
+    S.LoadTimeCommentVarNameGenerator =
+        std::make_unique<ASTNameGenerator>(S.Context);
+  if (!S.getLangOpts().isLoadTimeCommentVar(
+          S.LoadTimeCommentVarNameGenerator->getName(VD)))
+    return;
+
+  std::optional<unsigned> Reason;
+  if (VD->isLocalVarDecl())
+    // Only file- and namespace-scope variables are supported. A name match
+    // on anything else demonstrates intent (scope participates in the
+    // mangled name), so the unsupported kinds are diagnosed rather than
+    // silently ignored.
+    Reason = diag::LoadTimeCommentVarReason::FunctionLocal;
+  else if (isa<VarTemplateSpecializationDecl>(VD))
+    Reason = diag::LoadTimeCommentVarReason::TemplateSpecialization;
+  else if (VD->isStaticDataMember())
+    Reason = diag::LoadTimeCommentVarReason::StaticDataMember;
+  else if (Pointee.isNull() ||
+           !S.Context.hasSameUnqualifiedType(Pointee, S.Context.CharTy))
+    // Only plain `char` pointers/arrays are supported. A name match on a
+    // variable of any other type (int, struct, wide or explicitly
+    // signed/unsigned character types, ...) still demonstrates intent, so it
+    // is diagnosed.
+    Reason = diag::LoadTimeCommentVarReason::UnsupportedType;
+  else if (VD->getStorageDuration() != SD_Static)
+    // The string must have static storage duration; a thread-local variable
+    // is not preserved.
+    Reason = diag::LoadTimeCommentVarReason::BadStorage;
+  else if (Ty.isVolatileQualified() || Pointee.isVolatileQualified())
+    // The intended usage does not intersect with use cases where the character
+    // array or the pointer to it is volatile-qualified; such variables are not
+    // preserved.
+    Reason = diag::LoadTimeCommentVarReason::Volatile;
+  else if (!VD->hasConstantInitialization())
+    // The string has to be present in the object at load time. A dynamically
+    // initialized variable only gets its value from a startup constructor, so
+    // the object would not contain the intended string.
+    Reason = diag::LoadTimeCommentVarReason::DynamicInit;
+  else if (PT && !isa<StringLiteral>(VD->getInit()->IgnoreParenImpCasts()))
----------------
hubert-reinterpretcast wrote:

Please check to see if this works for a string literal in braces.
C/C++:
```c
static const char *bracedScalar = {"Hello, world!"};
```

C++:
```cpp
static const char *braceInit{"Unicorn!"};
```

https://github.com/llvm/llvm-project/pull/187986
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to