Drop support of #pragma cling load header.h

llvm-mirror/clang@444665e219 says:
"Remove use of lookahead from _Pragma handling and from all other

internal lexing steps in the preprocessor.

It is not safe to use the preprocessor's token lookahead except when
operating on the final sequence of tokens that would be produced by
phase 4 of translation. Doing so corrupts the token lookahead cache used
by the parser. (See added testcase for an example.) Lookahead should
instead be viewed as a layer on top of the normal lexer.

Added assertions to catch any further incorrect uses of lookahead within
lexing actions."

This tells us that if we try to #include the header.h while processing the
This commit is contained in:
Vassil Vassilev 2020-08-25 19:29:40 +00:00 committed by jenkins
parent 6a66cbd1df
commit 2d1a60d163
3 changed files with 21 additions and 72 deletions

View File

@ -126,19 +126,23 @@ namespace {
return;
// Need to parse them all until the end to handle the possible
// #include stements that will be generated
std::vector<std::string> Files;
Files.push_back(std::move(Literal));
// #include statements that will be generated
struct LibraryFileInfo {
std::string FileName;
SourceLocation StartLoc;
};
std::vector<LibraryFileInfo> FileInfos;
FileInfos.push_back({std::move(Literal), Tok.getLocation()});
while (GetNextLiteral(PP, Tok, Literal, kLoadFile))
Files.push_back(std::move(Literal));
FileInfos.push_back({std::move(Literal), Tok.getLocation()});
clang::Parser& P = m_Interp.getParser();
Parser::ParserCurTokRestoreRAII savedCurToken(P);
// After we have saved the token reset the current one to something
// which is safe (semi colon usually means empty decl)
Token& CurTok = const_cast<Token&>(P.getCurToken());
CurTok.setKind(tok::semi);
Preprocessor::CleanupAndRestoreCacheRAII cleanupRAII(PP);
// We can't PushDeclContext, because we go up and the routine that
// pops the DeclContext assumes that we drill down always.
@ -150,9 +154,15 @@ namespace {
TU, m_Interp.getSema().TUScope);
Interpreter::PushTransactionRAII pushedT(&m_Interp);
for (std::string& File : Files) {
if (m_Interp.loadFile(File, true) != Interpreter::kSuccess)
for (const LibraryFileInfo& FI : FileInfos) {
// FIXME: Consider the case where the library static init section has
// a call to interpreter parsing header file. It will suffer the same
// issue as if we included the file within the pragma.
if (m_Interp.loadLibrary(FI.FileName, true) != Interpreter::kSuccess) {
PP.Diag(FI.StartLoc, diag::err_expected)
<< "is not a library; did you mean #include \"" + FI.FileName + "\"";
return;
}
}
}

View File

@ -10,6 +10,7 @@
// RUN: cat %s | %cling -L %T -Xclang -verify 2>&1 | FileCheck %s
#pragma cling load("DoesNotExistPleaseRecover")
// expected-error@input_line_13:1{{expected is not a library; did you mean #include "DoesNotExistPleaseRecover"}}
// expected-error@input_line_13:1{{'DoesNotExistPleaseRecover' file not found}}
#pragma cling load("libcall_lib")

View File

@ -6,70 +6,8 @@
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
// RUN: cat %s | %cling -I%S -Xclang -verify 2>&1 | FileCheck %s
// RUN: cat %s | %cling -I%S -Xclang -verify 2>&1
// FIXME: When printing can be properly unloaded don't force it here
"BEGIN"
// CHECK: (const char [6]) "BEGIN"
#pragma cling load("P0.h", "P1.h","P2.h")
ValueA
// CHECK-NEXT: (const char *) "ValueA"
ValueB
// CHECK-NEXT: (const char *) "ValueB"
ValueC
// CHECK-NEXT: (const char *) "ValueC"
.undo
.undo
.undo
.undo
// FIXME: When print Transactions are properly parenteted remove these
.undo
.undo
.undo
ValueA // expected-error {{use of undeclared identifier 'ValueA'}}
#pragma cling load "P0.h" "P1.h" "P2.h"
ValueA
// CHECK-NEXT: (const char *) "ValueA"
ValueB
// CHECK-NEXT: (const char *) "ValueB"
ValueC
// CHECK-NEXT: (const char *) "ValueC"
.undo
.undo
.undo
.undo
// FIXME: When print Transactions are properly parenteted remove these
.undo
.undo
.undo
ValueB // expected-error {{use of undeclared identifier 'ValueB'}}
#pragma cling(load, "P0.h", "P1.h", "P2.h")
ValueA
// CHECK-NEXT: (const char *) "ValueA"
ValueB
// CHECK-NEXT: (const char *) "ValueB"
ValueC
// CHECK-NEXT: (const char *) "ValueC"
#pragma cling load "P0.h P1.h P2.h"
ValueD
// CHECK-NEXT: (const char *) "ValueD"
#pragma cling load("P0.h", "P1.h","P2.h") //expected-error {{expected is not a library; did you mean #include "P0.h"}}
.q