================
@@ -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