diff options
| author | Mariya Podchishchaeva <mariya.podchishchaeva@intel.com> | 2024-06-20 14:38:46 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-06-20 14:38:46 +0200 |
| commit | 41c6e4379204ffc00948edd33d59ba5ebbceaba2 (patch) | |
| tree | b8508b8f0e7f108d1f6759922f49f367bd24fb00 /clang/lib/Sema/SemaInit.cpp | |
| parent | af82e63c28f67bf61a9b2b0e64bc55be4acf520e (diff) | |
| download | llvm-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.cpp | 113 |
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); |
