Skip to content
Merged
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ Bug Fixes in This Version
(#GH159080)
- Fixed a failed assertion with empty filename arguments in ``__has_embed``. (#GH159898)
- Fixed a failed assertion with empty filename in ``#embed`` directive. (#GH162951)
- Fixed a crash triggered by unterminated ``__has_embed``. (#GH162953)

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Lex/PPDirectives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3648,14 +3648,14 @@ Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) {
std::pair<tok::TokenKind, SourceLocation> Matches) {
Diag(CurTok, diag::err_expected) << Expected;
Diag(Matches.second, diag::note_matching) << Matches.first;
if (CurTok.isNot(tok::eod))
if (CurTok.isNot(EndTokenKind))
DiscardUntilEndOfDirective(CurTok);
};

auto ExpectOrDiagAndSkipToEOD = [&](tok::TokenKind Kind) {
if (CurTok.isNot(Kind)) {
Diag(CurTok, diag::err_expected) << Kind;
if (CurTok.isNot(tok::eod))
if (CurTok.isNot(EndTokenKind))
DiscardUntilEndOfDirective(CurTok);
return false;
}
Expand Down Expand Up @@ -3746,7 +3746,7 @@ Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) {
if (Result.isNegative()) {
Diag(CurTok, diag::err_requires_positive_value)
<< toString(Result, 10) << /*positive*/ 0;
if (CurTok.isNot(tok::eod))
if (CurTok.isNot(EndTokenKind))
DiscardUntilEndOfDirective(CurTok);
return std::nullopt;
}
Expand Down Expand Up @@ -3889,7 +3889,7 @@ Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) {
}
if (!ForHasEmbed) {
Diag(ParamStartLoc, diag::err_pp_unknown_parameter) << 1 << Parameter;
if (CurTok.isNot(tok::eod))
if (CurTok.isNot(EndTokenKind))
DiscardUntilEndOfDirective(CurTok);
return std::nullopt;
}
Expand Down
10 changes: 4 additions & 6 deletions clang/lib/Lex/PPMacroExpansion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1262,16 +1262,11 @@ EmbedResult Preprocessor::EvaluateHasEmbed(Token &Tok, IdentifierInfo *II) {

std::optional<LexEmbedParametersResult> Params =
this->LexEmbedParameters(Tok, /*ForHasEmbed=*/true);
assert((Params || Tok.is(tok::eod)) &&
"expected success or to be at the end of the directive");

if (!Params)
return EmbedResult::Invalid;

if (Params->UnrecognizedParams > 0)
return EmbedResult::NotFound;

if (!Tok.is(tok::r_paren)) {
if (Tok.isNot(tok::r_paren)) {
Diag(this->getLocForEndOfToken(FilenameLoc), diag::err_pp_expected_after)
<< II << tok::r_paren;
Diag(LParenLoc, diag::note_matching) << tok::l_paren;
Expand All @@ -1280,6 +1275,9 @@ EmbedResult Preprocessor::EvaluateHasEmbed(Token &Tok, IdentifierInfo *II) {
return EmbedResult::Invalid;
}

if (Params->UnrecognizedParams > 0)
return EmbedResult::NotFound;

SmallString<128> FilenameBuffer;
StringRef Filename = this->getSpelling(FilenameTok, FilenameBuffer);
if (Filename.empty())
Expand Down
46 changes: 45 additions & 1 deletion clang/test/Preprocessor/embed___has_embed_parsing_errors.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
// RUN: %clang_cc1 -std=c23 %s -E -verify
// RUN: split-file %s %t
// RUN: %clang_cc1 -std=c23 -E -verify %t/test1.c
// RUN: %clang_cc1 -std=c23 -E -verify %t/test2.c
// RUN: %clang_cc1 -std=c23 -E -verify %t/test3.c
// RUN: %clang_cc1 -std=c23 -E -verify %t/test4.c
// RUN: %clang_cc1 -std=c23 -E -verify %t/test5.c
// RUN: %clang_cc1 -std=c23 -E -verify %t/test6.c

//--- test1.c

// Test the parsing behavior for __has_embed and all of its parameters to ensure we
// recover from failures gracefully.
Expand Down Expand Up @@ -250,3 +258,39 @@

#if __has_embed("") // expected-error {{empty filename}}
#endif

//--- test2.c
// expected-error@+4 {{missing ')' after '__has_embed'}} \
expected-error@+4 {{expected value in expression}} \
expected-note@+4 {{to match this '('}} \
expected-error@+4 {{unterminated conditional directive}}
#if __has_embed (__FILE__ foo limit(1)

//--- test3.c
// expected-error@+4 {{missing ')' after '__has_embed'}} \
expected-error@+4 {{expected value in expression}} \
expected-note@+4 {{to match this '('}} \
expected-error@+4 {{unterminated conditional directive}}
#if __has_embed (__FILE__ foo

//--- test4.c
// expected-error@+4 {{missing ')' after '__has_embed'}} \
expected-error@+4 {{expected value in expression}} \
expected-note@+4 {{to match this '('}} \
expected-error@+4 {{unterminated conditional directive}}
#if __has_embed ("a" foo()

//--- test5.c
// expected-error@+4 {{missing ')' after '__has_embed'}} \
expected-error@+4 {{expected value in expression}} \
expected-note@+4 {{to match this '('}} \
expected-error@+4 {{unterminated conditional directive}}
#if __has_embed ("a" bar() foo

//--- test6.c
// expected-error@+4 {{missing ')' after '__has_embed'}} \
expected-error@+4 {{expected value in expression}} \
expected-note@+4 {{to match this '('}} \
expected-error@+4 {{unterminated conditional directive}}
#if __has_embed (__FILE__ limit(1) foo
int a = __has_embed (__FILE__);