Skip to content

Commit

Permalink
[clang] Be careful when choosing "fast path" for initialization with …
Browse files Browse the repository at this point in the history
…#embed (#99023)

When #embed appears in an initializer list, we may choose a "fast path"
if the target declaration is a char array. We simply initialize it with
string literal that contains embedded data. However we need to be
careful when checking that we actually can use this "fast path" since
char array may be nested in a struct.
  • Loading branch information
Fznamznon authored Jul 17, 2024
1 parent 5e338f1 commit a5b5208
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 4 deletions.
17 changes: 13 additions & 4 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1993,9 +1993,18 @@ static bool checkDestructorReference(QualType ElementType, SourceLocation Loc,
return SemaRef.DiagnoseUseOfDecl(Destructor, Loc);
}

static bool canInitializeArrayWithEmbedDataString(ArrayRef<Expr *> ExprList,
QualType InitType,
ASTContext &Context) {
static bool
canInitializeArrayWithEmbedDataString(ArrayRef<Expr *> ExprList,
const InitializedEntity &Entity,
ASTContext &Context) {
QualType InitType = Entity.getType();
const InitializedEntity *Parent = &Entity;

while (Parent) {
InitType = Parent->getType();
Parent = Parent->getParent();
}

// Only one initializer, it's an embed and the types match;
EmbedExpr *EE =
ExprList.size() == 1
Expand Down Expand Up @@ -2034,7 +2043,7 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
}
}

if (canInitializeArrayWithEmbedDataString(IList->inits(), DeclType,
if (canInitializeArrayWithEmbedDataString(IList->inits(), Entity,
SemaRef.Context)) {
EmbedExpr *Embed = cast<EmbedExpr>(IList->inits()[0]);
IList->setInit(0, Embed->getDataStringLiteral());
Expand Down
8 changes: 8 additions & 0 deletions clang/test/Preprocessor/embed_codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// CHECK: @__const._Z3fooi.ca = private unnamed_addr constant [3 x i32] [i32 0, i32 106, i32 107], align 4
// CHECK: @__const._Z3fooi.sc = private unnamed_addr constant %struct.S1 { i32 106, i32 107, i32 0 }, align 4
// CHECK: @__const._Z3fooi.t = private unnamed_addr constant [3 x %struct.T] [%struct.T { [2 x i32] [i32 48, i32 49], %struct.S1 { i32 50, i32 51, i32 52 } }, %struct.T { [2 x i32] [i32 53, i32 54], %struct.S1 { i32 55, i32 56, i32 57 } }, %struct.T { [2 x i32] [i32 10, i32 0], %struct.S1 zeroinitializer }], align 16
// CHECK: @__const._Z3fooi.W = private unnamed_addr constant %struct.Wrapper { i32 48, %struct.HasCharArray { [10 x i8] c"123456789\0A" } }, align 4
void foo(int a) {
// CHECK: %a.addr = alloca i32, align 4
// CHECK: store i32 %a, ptr %a.addr, align 4
Expand Down Expand Up @@ -82,4 +83,11 @@ struct T tnonc[] = {
#embed <jk.txt> prefix(,)
};


struct HasCharArray { unsigned char h[10]; };
struct Wrapper { int a; struct HasCharArray d; };
constexpr struct Wrapper W = {
#embed "numbers.txt"
};

}
8 changes: 8 additions & 0 deletions clang/test/Preprocessor/embed_constexpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,11 @@ struct ST {};
ST<
#embed <jk.txt> limit(1)
> st;

struct HasCharArray { unsigned char h[10]; };
struct Wrapper { int a; struct HasCharArray d; };
constexpr struct Wrapper W = {
#embed "numbers.txt"
};

static_assert(W.d.h[2] == '3');

0 comments on commit a5b5208

Please sign in to comment.