Serialize #pragma redefine_extname into precompiled headers. (#186755)

Also deserialize them back again on reading.

The implementation is based on the existing implementation of `#pragma
weak` serialization.

Fixes issue #186742.

---------

Co-authored-by: Chuanqi Xu <yedeng.yd@linux.alibaba.com>
This commit is contained in:
divVerent 2026-03-30 11:37:45 +02:00 committed by GitHub
parent be94bfd615
commit 475f71e8fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 150 additions and 1 deletions

View File

@ -163,6 +163,16 @@ public:
virtual void ReadWeakUndeclaredIdentifiers(
SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WI) {}
/// Read the set of #pragma redefine_extname'd, undeclared identifiers known
/// to the external Sema source.
///
/// The external source should append its own #pragma redefine_extname'd,
/// undeclared identifiers to the given vector. Note that this routine may be
/// invoked multiple times; the external source should take care not to
/// introduce the same identifiers repeatedly.
virtual void ReadExtnameUndeclaredIdentifiers(
SmallVectorImpl<std::pair<IdentifierInfo *, AsmLabelAttr *>> &EI) {}
/// Read the set of used vtables known to the external Sema source.
///
/// The external source should append its own used vtables to the given

View File

@ -310,6 +310,17 @@ public:
void ReadWeakUndeclaredIdentifiers(
SmallVectorImpl<std::pair<IdentifierInfo*, WeakInfo> > &WI) override;
/// Read the set of #pragma redefine_extname'd, undeclared identifiers known
/// to the external Sema source.
///
/// The external source should append its own #pragma redefine_extname'd,
/// undeclared identifiers to the given vector. Note that this routine may be
/// invoked multiple times; the external source should take care not to
/// introduce the same identifiers repeatedly.
void ReadExtnameUndeclaredIdentifiers(
SmallVectorImpl<std::pair<IdentifierInfo *, AsmLabelAttr *>> &EI)
override;
/// Read the set of used vtables known to the external Sema source.
///
/// The external source should append its own used vtables to the given

View File

@ -968,6 +968,10 @@ public:
/// Load weak undeclared identifiers from the external source.
void LoadExternalWeakUndeclaredIdentifiers();
/// Load #pragma redefine_extname'd undeclared identifiers from the external
/// source.
void LoadExternalExtnameUndeclaredIdentifiers();
/// Determine if VD, which must be a variable or function, is an external
/// symbol that nonetheless can't be referenced from outside this translation
/// unit because its type has no linkage and it's not extern "C".

View File

@ -748,6 +748,9 @@ enum ASTRecordTypes {
/// Record code for #pragma clang riscv intrinsic vector.
RISCV_VECTOR_INTRINSICS_PRAGMA = 78,
/// Record code for extname-redefined undeclared identifiers.
EXTNAME_UNDECLARED_IDENTIFIERS = 79,
};
/// Record types used within a source manager block.

View File

@ -965,9 +965,15 @@ private:
SmallVector<serialization::SelectorID, 64> ReferencedSelectorsData;
/// A snapshot of Sema's weak undeclared identifier tracking, for
/// generating warnings.
/// generating warnings. Note that this vector has 3n entries, being triplets
/// of the form C name, alias if any, and source location.
SmallVector<serialization::IdentifierID, 64> WeakUndeclaredIdentifiers;
/// A snapshot of Sema's #redefine_extname'd undeclared identifier tracking,
/// for generating warnings. Note that this vector has 3n entries, being
/// triplets in the order of C name, asm name, and source location.
SmallVector<serialization::IdentifierID, 64> ExtnameUndeclaredIdentifiers;
/// The IDs of type aliases for ext_vectors that exist in the chain.
///
/// Used by Sema for finding sugared names for ext_vectors in diagnostics.
@ -2356,6 +2362,10 @@ public:
void ReadWeakUndeclaredIdentifiers(
SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo>> &WeakIDs) override;
void ReadExtnameUndeclaredIdentifiers(
SmallVectorImpl<std::pair<IdentifierInfo *, AsmLabelAttr *>> &ExtnameIDs)
override;
void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) override;
void ReadPendingInstantiations(

View File

@ -317,6 +317,12 @@ void MultiplexExternalSemaSource::ReadWeakUndeclaredIdentifiers(
Sources[i]->ReadWeakUndeclaredIdentifiers(WI);
}
void MultiplexExternalSemaSource::ReadExtnameUndeclaredIdentifiers(
SmallVectorImpl<std::pair<IdentifierInfo *, AsmLabelAttr *>> &EI) {
for (size_t i = 0; i < Sources.size(); ++i)
Sources[i]->ReadExtnameUndeclaredIdentifiers(EI);
}
void MultiplexExternalSemaSource::ReadUsedVTables(
SmallVectorImpl<ExternalVTableUse> &VTables) {
for(size_t i = 0; i < Sources.size(); ++i)

View File

@ -1089,6 +1089,15 @@ void Sema::LoadExternalWeakUndeclaredIdentifiers() {
(void)WeakUndeclaredIdentifiers[WeakID.first].insert(WeakID.second);
}
void Sema::LoadExternalExtnameUndeclaredIdentifiers() {
if (!ExternalSource)
return;
SmallVector<std::pair<IdentifierInfo *, AsmLabelAttr *>, 4> ExtnameIDs;
ExternalSource->ReadExtnameUndeclaredIdentifiers(ExtnameIDs);
for (auto &ExtnameID : ExtnameIDs)
ExtnameUndeclaredIdentifiers[ExtnameID.first] = ExtnameID.second;
}
typedef llvm::DenseMap<const CXXRecordDecl*, bool> RecordCompleteMap;

View File

@ -8241,6 +8241,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}
LoadExternalExtnameUndeclaredIdentifiers();
if (Expr *E = D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
@ -10545,6 +10547,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
isMemberSpecialization ||
isFunctionTemplateSpecialization);
LoadExternalExtnameUndeclaredIdentifiers();
// Handle GNU asm-label extension (encoded as an attribute).
if (Expr *E = D.getAsmLabel()) {
// The parser guarantees this is a string.

View File

@ -19,6 +19,7 @@
#include "clang/AST/ASTStructuralEquivalence.h"
#include "clang/AST/ASTUnresolvedSet.h"
#include "clang/AST/AbstractTypeReader.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
@ -4032,6 +4033,27 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
}
break;
case EXTNAME_UNDECLARED_IDENTIFIERS:
if (Record.size() % 3 != 0)
return llvm::createStringError(std::errc::illegal_byte_sequence,
"invalid extname identifiers record");
// FIXME: Ignore #pragma redefine_extname'd, undeclared identifiers from
// non-original PCH files. This isn't the way to do it :)
ExtnameUndeclaredIdentifiers.clear();
// Translate the #pragma redefine_extname'd, undeclared identifiers into
// global IDs.
for (unsigned I = 0, N = Record.size(); I < N; /* in loop */) {
ExtnameUndeclaredIdentifiers.push_back(
getGlobalIdentifierID(F, Record[I++]));
ExtnameUndeclaredIdentifiers.push_back(
getGlobalIdentifierID(F, Record[I++]));
ExtnameUndeclaredIdentifiers.push_back(
ReadSourceLocation(F, Record, I).getRawEncoding());
}
break;
case SELECTOR_OFFSETS: {
F.SelectorOffsets = (const uint32_t *)Blob.data();
F.LocalNumSelectors = Record[0];
@ -9691,6 +9713,27 @@ void ASTReader::ReadWeakUndeclaredIdentifiers(
WeakUndeclaredIdentifiers.clear();
}
void ASTReader::ReadExtnameUndeclaredIdentifiers(
SmallVectorImpl<std::pair<IdentifierInfo *, AsmLabelAttr *>> &ExtnameIDs) {
if (ExtnameUndeclaredIdentifiers.empty())
return;
for (unsigned I = 0, N = ExtnameUndeclaredIdentifiers.size(); I < N; I += 3) {
IdentifierInfo *NameId =
DecodeIdentifierInfo(ExtnameUndeclaredIdentifiers[I]);
IdentifierInfo *ExtnameId =
DecodeIdentifierInfo(ExtnameUndeclaredIdentifiers[I+1]);
SourceLocation Loc =
SourceLocation::getFromRawEncoding(ExtnameUndeclaredIdentifiers[I+2]);
AsmLabelAttr *Attr = AsmLabelAttr::CreateImplicit(
getContext(), ExtnameId->getName(),
AttributeCommonInfo(ExtnameId, SourceRange(Loc),
AttributeCommonInfo::Form::Pragma()));
ExtnameIDs.push_back(std::make_pair(NameId, Attr));
}
ExtnameUndeclaredIdentifiers.clear();
}
void ASTReader::ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) {
for (unsigned Idx = 0, N = VTableUses.size(); Idx < N; /* In loop */) {
ExternalVTableUse VT;

View File

@ -941,6 +941,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(TU_UPDATE_LEXICAL);
RECORD(SEMA_DECL_REFS);
RECORD(WEAK_UNDECLARED_IDENTIFIERS);
RECORD(EXTNAME_UNDECLARED_IDENTIFIERS);
RECORD(PENDING_IMPLICIT_INSTANTIATIONS);
RECORD(UPDATE_VISIBLE);
RECORD(DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD);
@ -6097,6 +6098,22 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema *SemaPtr, StringRef isysroot,
}
}
// Write the set of #pragma redefine_extname'd, undeclared identifiers. We
// always write the entire table, since later PCH files in a PCH chain are
// only interested in the results at the end of the chain.
RecordData ExtnameUndeclaredIdentifiers;
if (SemaPtr && !isWritingStdCXXNamedModules()) {
ASTContext &Context = SemaPtr->Context;
ASTRecordWriter ExtnameUndeclaredIdentifiersWriter(
Context, *this, ExtnameUndeclaredIdentifiers);
for (const auto &[II, AL] : SemaPtr->ExtnameUndeclaredIdentifiers) {
ExtnameUndeclaredIdentifiersWriter.AddIdentifierRef(II);
ExtnameUndeclaredIdentifiersWriter.AddIdentifierRef(
&Context.Idents.get(AL->getLabel()));
ExtnameUndeclaredIdentifiersWriter.AddSourceLocation(AL->getLocation());
}
}
// Form the record of special types.
RecordData SpecialTypes;
if (SemaPtr) {
@ -6244,6 +6261,12 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema *SemaPtr, StringRef isysroot,
Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS,
WeakUndeclaredIdentifiers);
// Write the record containing #pragma redefine_extname'd undeclared
// identifiers.
if (!ExtnameUndeclaredIdentifiers.empty())
Stream.EmitRecord(EXTNAME_UNDECLARED_IDENTIFIERS,
ExtnameUndeclaredIdentifiers);
if (!WritingModule) {
// Write the submodules that were imported, if any.
struct ModuleInfo {

View File

@ -0,0 +1,14 @@
/// Test this without pch.
// RUN: %clang_cc1 -triple=x86_64-unknown-linux -include %S/pragma-redefine-extname.h %s -verify -emit-llvm -o - | FileCheck %s
/// Test with pch.
// RUN: %clang_cc1 -triple=x86_64-unknown-linux -x c-header -emit-pch -o %t %S/pragma-redefine-extname.h
// RUN: %clang_cc1 -triple=x86_64-unknown-linux -include-pch %t %s -verify -emit-llvm -o - | FileCheck %s
// CHECK: define dso_local void @redeffunc2_ext
// CHECK: call void @redeffunc1_ext
/// Issue #186742: check that #pragma redefine_extname exports into PCHs even if the header contains no declaration of the symbol
void undecfunc1(void);
void undecfunc2(void) { undecfunc1(); }
static void undecfunc3(void) {} // expected-warning {{#pragma redefine_extname is applicable to external C declarations only; not applied to function 'undecfunc3'}}

View File

@ -0,0 +1,5 @@
// Header for PCH test pragma-redefine-extname.c
#pragma redefine_extname undecfunc1 redeffunc1_ext
#pragma redefine_extname undecfunc2 redeffunc2_ext
#pragma redefine_extname undecfunc3 redeffunc3_ext

View File

@ -582,6 +582,13 @@ public:
Source->ReadWeakUndeclaredIdentifiers(WI);
}
void ReadExtnameUndeclaredIdentifiers(
llvm::SmallVectorImpl<std::pair<clang::IdentifierInfo *,
clang::AsmLabelAttr *>> &EI) override {
for (auto &Source : Sources)
Source->ReadExtnameUndeclaredIdentifiers(EI);
}
void ReadUsedVTables(
llvm::SmallVectorImpl<clang::ExternalVTableUse> &VTables) override {
for (auto &Source : Sources)