aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaInit.cpp
diff options
context:
space:
mode:
authorMariya Podchishchaeva <mariya.podchishchaeva@intel.com>2024-06-20 14:38:46 +0200
committerGitHub <noreply@github.com>2024-06-20 14:38:46 +0200
commit41c6e4379204ffc00948edd33d59ba5ebbceaba2 (patch)
treeb8508b8f0e7f108d1f6759922f49f367bd24fb00 /clang/lib/Sema/SemaInit.cpp
parentaf82e63c28f67bf61a9b2b0e64bc55be4acf520e (diff)
downloadllvm-41c6e4379204ffc00948edd33d59ba5ebbceaba2.zip
llvm-41c6e4379204ffc00948edd33d59ba5ebbceaba2.tar.gz
llvm-41c6e4379204ffc00948edd33d59ba5ebbceaba2.tar.bz2
Reland [clang][Sema, Lex, Parse] Preprocessor embed in C and C++ (#95802)
This commit implements the entirety of the now-accepted [N3017 -Preprocessor Embed](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3017.htm) and its sister C++ paper [p1967](https://wg21.link/p1967). It implements everything in the specification, and includes an implementation that drastically improves the time it takes to embed data in specific scenarios (the initialization of character type arrays). The mechanisms used to do this are used under the "as-if" rule, and in general when the system cannot detect it is initializing an array object in a variable declaration, will generate EmbedExpr AST node which will be expanded by AST consumers (CodeGen or constant expression evaluators) or expand embed directive as a comma expression. This reverts commit https://github.com/llvm/llvm-project/commit/682d461d5a231cee54d65910e6341769419a67d7. --------- Co-authored-by: The Phantom Derpstorm <phdofthehouse@gmail.com> Co-authored-by: Aaron Ballman <aaron@aaronballman.com> Co-authored-by: cor3ntin <corentinjabot@gmail.com> Co-authored-by: H. Vetinari <h.vetinari@gmx.com>
Diffstat (limited to 'clang/lib/Sema/SemaInit.cpp')
-rw-r--r--clang/lib/Sema/SemaInit.cpp113
1 files changed, 100 insertions, 13 deletions
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 4947872..dbe2231 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -313,6 +313,8 @@ class InitListChecker {
InitListExpr *FullyStructuredList = nullptr;
NoInitExpr *DummyExpr = nullptr;
SmallVectorImpl<QualType> *AggrDeductionCandidateParamTypes = nullptr;
+ EmbedExpr *CurEmbed = nullptr; // Save current embed we're processing.
+ unsigned CurEmbedIndex = 0;
NoInitExpr *getDummyInit() {
if (!DummyExpr)
@@ -501,6 +503,42 @@ class InitListChecker {
void CheckEmptyInitializable(const InitializedEntity &Entity,
SourceLocation Loc);
+ Expr *HandleEmbed(EmbedExpr *Embed, const InitializedEntity &Entity) {
+ Expr *Result = nullptr;
+ // Undrestand which part of embed we'd like to reference.
+ if (!CurEmbed) {
+ CurEmbed = Embed;
+ CurEmbedIndex = 0;
+ }
+ // Reference just one if we're initializing a single scalar.
+ uint64_t ElsCount = 1;
+ // Otherwise try to fill whole array with embed data.
+ if (Entity.getKind() == InitializedEntity::EK_ArrayElement) {
+ ValueDecl *ArrDecl = Entity.getParent()->getDecl();
+ auto *AType = SemaRef.Context.getAsArrayType(ArrDecl->getType());
+ assert(AType && "expected array type when initializing array");
+ ElsCount = Embed->getDataElementCount();
+ if (const auto *CAType = dyn_cast<ConstantArrayType>(AType))
+ ElsCount = std::min(CAType->getSize().getZExtValue(),
+ ElsCount - CurEmbedIndex);
+ if (ElsCount == Embed->getDataElementCount()) {
+ CurEmbed = nullptr;
+ CurEmbedIndex = 0;
+ return Embed;
+ }
+ }
+
+ Result = new (SemaRef.Context)
+ EmbedExpr(SemaRef.Context, Embed->getLocation(), Embed->getData(),
+ CurEmbedIndex, ElsCount);
+ CurEmbedIndex += ElsCount;
+ if (CurEmbedIndex >= Embed->getDataElementCount()) {
+ CurEmbed = nullptr;
+ CurEmbedIndex = 0;
+ }
+ return Result;
+ }
+
public:
InitListChecker(
Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T,
@@ -1473,6 +1511,9 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// Brace elision is never performed if the element is not an
// assignment-expression.
if (Seq || isa<InitListExpr>(expr)) {
+ if (auto *Embed = dyn_cast<EmbedExpr>(expr)) {
+ expr = HandleEmbed(Embed, Entity);
+ }
if (!VerifyOnly) {
ExprResult Result = Seq.Perform(SemaRef, TmpEntity, Kind, expr);
if (Result.isInvalid())
@@ -1486,7 +1527,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
UpdateStructuredListElement(StructuredList, StructuredIndex,
getDummyInit());
}
- ++Index;
+ if (!CurEmbed)
+ ++Index;
if (AggrDeductionCandidateParamTypes)
AggrDeductionCandidateParamTypes->push_back(ElemType);
return;
@@ -1679,6 +1721,8 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
++Index;
++StructuredIndex;
return;
+ } else if (auto *Embed = dyn_cast<EmbedExpr>(expr)) {
+ expr = HandleEmbed(Embed, Entity);
}
ExprResult Result;
@@ -1700,14 +1744,16 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
else {
ResultExpr = Result.getAs<Expr>();
- if (ResultExpr != expr && !VerifyOnly) {
+ if (ResultExpr != expr && !VerifyOnly && !CurEmbed) {
// The type was promoted, update initializer list.
// FIXME: Why are we updating the syntactic init list?
IList->setInit(Index, ResultExpr);
}
}
+
UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr);
- ++Index;
+ if (!CurEmbed)
+ ++Index;
if (AggrDeductionCandidateParamTypes)
AggrDeductionCandidateParamTypes->push_back(DeclType);
}
@@ -1946,6 +1992,30 @@ static bool checkDestructorReference(QualType ElementType, SourceLocation Loc,
return SemaRef.DiagnoseUseOfDecl(Destructor, Loc);
}
+static bool canInitializeArrayWithEmbedDataString(ArrayRef<Expr *> ExprList,
+ QualType InitType,
+ ASTContext &Context) {
+ // Only one initializer, it's an embed and the types match;
+ EmbedExpr *EE =
+ ExprList.size() == 1
+ ? dyn_cast_if_present<EmbedExpr>(ExprList[0]->IgnoreParens())
+ : nullptr;
+ if (!EE)
+ return false;
+
+ if (InitType->isArrayType()) {
+ const ArrayType *InitArrayType = InitType->getAsArrayTypeUnsafe();
+ QualType InitElementTy = InitArrayType->getElementType();
+ QualType EmbedExprElementTy = EE->getType();
+ const bool TypesMatch =
+ Context.typesAreCompatible(InitElementTy, EmbedExprElementTy) ||
+ (InitElementTy->isCharType() && EmbedExprElementTy->isCharType());
+ if (TypesMatch)
+ return true;
+ }
+ return false;
+}
+
void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
@@ -1963,6 +2033,12 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
}
}
+ if (canInitializeArrayWithEmbedDataString(IList->inits(), DeclType,
+ SemaRef.Context)) {
+ EmbedExpr *Embed = cast<EmbedExpr>(IList->inits()[0]);
+ IList->setInit(0, Embed->getDataStringLiteral());
+ }
+
// Check for the special-case of initializing an array with a string.
if (Index < IList->getNumInits()) {
if (IsStringInit(IList->getInit(Index), arrayType, SemaRef.Context) ==
@@ -2065,13 +2141,24 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
if (maxElementsKnown && elementIndex == maxElements)
break;
- InitializedEntity ElementEntity =
- InitializedEntity::InitializeElement(SemaRef.Context, StructuredIndex,
- Entity);
+ InitializedEntity ElementEntity = InitializedEntity::InitializeElement(
+ SemaRef.Context, StructuredIndex, Entity);
+
+ unsigned EmbedElementIndexBeforeInit = CurEmbedIndex;
// Check this element.
CheckSubElementType(ElementEntity, IList, elementType, Index,
StructuredList, StructuredIndex);
++elementIndex;
+ if ((CurEmbed || isa<EmbedExpr>(Init)) && elementType->isScalarType()) {
+ if (CurEmbed) {
+ elementIndex =
+ elementIndex + CurEmbedIndex - EmbedElementIndexBeforeInit - 1;
+ } else {
+ auto Embed = cast<EmbedExpr>(Init);
+ elementIndex = elementIndex + Embed->getDataElementCount() -
+ EmbedElementIndexBeforeInit - 1;
+ }
+ }
// If the array is of incomplete type, keep track of the number of
// elements in the initializer.
@@ -9077,19 +9164,18 @@ ExprResult InitializationSequence::Perform(Sema &S,
}
}
}
-
+ Expr *Init = CurInit.get();
CheckedConversionKind CCK =
Kind.isCStyleCast() ? CheckedConversionKind::CStyleCast
: Kind.isFunctionalCast() ? CheckedConversionKind::FunctionalCast
: Kind.isExplicitCast() ? CheckedConversionKind::OtherCast
: CheckedConversionKind::Implicit;
- ExprResult CurInitExprRes =
- S.PerformImplicitConversion(CurInit.get(), Step->Type, *Step->ICS,
- getAssignmentAction(Entity), CCK);
+ ExprResult CurInitExprRes = S.PerformImplicitConversion(
+ Init, Step->Type, *Step->ICS, getAssignmentAction(Entity), CCK);
if (CurInitExprRes.isInvalid())
return ExprError();
- S.DiscardMisalignedMemberAddress(Step->Type.getTypePtr(), CurInit.get());
+ S.DiscardMisalignedMemberAddress(Step->Type.getTypePtr(), Init);
CurInit = CurInitExprRes;
@@ -9244,10 +9330,11 @@ ExprResult InitializationSequence::Perform(Sema &S,
case SK_CAssignment: {
QualType SourceType = CurInit.get()->getType();
+ Expr *Init = CurInit.get();
// Save off the initial CurInit in case we need to emit a diagnostic
- ExprResult InitialCurInit = CurInit;
- ExprResult Result = CurInit;
+ ExprResult InitialCurInit = Init;
+ ExprResult Result = Init;
Sema::AssignConvertType ConvTy =
S.CheckSingleAssignmentConstraints(Step->Type, Result, true,
Entity.getKind() == InitializedEntity::EK_Parameter_CF_Audited);