Skip to content

Commit 3a5c9b7

Browse files
committed
[APINotes] Upstream Parser support for API Notes
1 parent 447aabf commit 3a5c9b7

File tree

6 files changed

+90
-1
lines changed

6 files changed

+90
-1
lines changed

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,6 +1609,9 @@ def err_pragma_invalid_keyword : Error<
16091609
def err_pragma_pipeline_invalid_keyword : Error<
16101610
"invalid argument; expected 'disable'">;
16111611

1612+
// API notes.
1613+
def err_type_unparsed : Error<"unparsed tokens following type">;
1614+
16121615
// Pragma unroll support.
16131616
def warn_pragma_unroll_cuda_value_in_parens : Warning<
16141617
"argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">,

clang/include/clang/Lex/Lexer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,11 +198,11 @@ class Lexer : public PreprocessorLexer {
198198
/// from. Currently this is only used by _Pragma handling.
199199
SourceLocation getFileLoc() const { return FileLoc; }
200200

201-
private:
202201
/// Lex - Return the next token in the file. If this is the end of file, it
203202
/// return the tok::eof token. This implicitly involves the preprocessor.
204203
bool Lex(Token &Result);
205204

205+
private:
206206
/// Called when the preprocessor is in 'dependency scanning lexing mode'.
207207
bool LexDependencyDirectiveToken(Token &Result);
208208

clang/include/clang/Parse/Parser.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3655,6 +3655,18 @@ class Parser : public CodeCompletionHandler {
36553655
ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
36563656
SourceLocation &DeclEnd);
36573657

3658+
/// Parse the given string as a type.
3659+
///
3660+
/// This is a dangerous utility function currently employed only by API notes.
3661+
/// It is not a general entry-point for safely parsing types from strings.
3662+
///
3663+
/// \param TypeStr The string to be parsed as a type.
3664+
/// \param Context The name of the context in which this string is being
3665+
/// parsed, which will be used in diagnostics.
3666+
/// \param IncludeLoc The location at which this parse was triggered.
3667+
TypeResult ParseTypeFromString(StringRef TypeStr, StringRef Context,
3668+
SourceLocation IncludeLoc);
3669+
36583670
//===--------------------------------------------------------------------===//
36593671
// Modules
36603672
DeclGroupPtrTy ParseModuleDecl(Sema::ModuleImportState &ImportState);

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,10 @@ class Sema final {
955955
OpaqueParser = P;
956956
}
957957

958+
/// Callback to the parser to parse a type expressed as a string.
959+
std::function<TypeResult(StringRef, StringRef, SourceLocation)>
960+
ParseTypeFromStringCallback;
961+
958962
class DelayedDiagnostics;
959963

960964
class DelayedDiagnosticsState {

clang/lib/Parse/ParseDecl.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8051,6 +8051,71 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
80518051
return false;
80528052
}
80538053

8054+
TypeResult Parser::ParseTypeFromString(StringRef TypeStr, StringRef Context,
8055+
SourceLocation IncludeLoc) {
8056+
// Consume (unexpanded) tokens up to the end-of-directive.
8057+
SmallVector<Token, 4> Tokens;
8058+
{
8059+
// Create a new buffer from which we will parse the type.
8060+
auto &SourceMgr = PP.getSourceManager();
8061+
FileID FID = SourceMgr.createFileID(
8062+
llvm::MemoryBuffer::getMemBufferCopy(TypeStr, Context), SrcMgr::C_User,
8063+
0, 0, IncludeLoc);
8064+
8065+
// Form a new lexer that references the buffer.
8066+
Lexer L(FID, SourceMgr.getBufferOrFake(FID), PP);
8067+
L.setParsingPreprocessorDirective(true);
8068+
8069+
// Lex the tokens from that buffer.
8070+
Token Tok;
8071+
do {
8072+
L.Lex(Tok);
8073+
Tokens.push_back(Tok);
8074+
} while (Tok.isNot(tok::eod));
8075+
}
8076+
8077+
// Replace the "eod" token with an "eof" token identifying the end of
8078+
// the provided string.
8079+
Token &EndToken = Tokens.back();
8080+
EndToken.startToken();
8081+
EndToken.setKind(tok::eof);
8082+
EndToken.setLocation(Tok.getLocation());
8083+
EndToken.setEofData(TypeStr.data());
8084+
8085+
// Add the current token back.
8086+
Tokens.push_back(Tok);
8087+
8088+
// Enter the tokens into the token stream.
8089+
PP.EnterTokenStream(Tokens, /*DisableMacroExpansion=*/false,
8090+
/*IsReinject=*/false);
8091+
8092+
// Consume the current token so that we'll start parsing the tokens we
8093+
// added to the stream.
8094+
ConsumeAnyToken();
8095+
8096+
// Enter a new scope.
8097+
ParseScope LocalScope(this, 0);
8098+
8099+
// Parse the type.
8100+
TypeResult Result = ParseTypeName(nullptr);
8101+
8102+
// Check if we parsed the whole thing.
8103+
if (Result.isUsable() &&
8104+
(Tok.isNot(tok::eof) || Tok.getEofData() != TypeStr.data())) {
8105+
Diag(Tok.getLocation(), diag::err_type_unparsed);
8106+
}
8107+
8108+
// There could be leftover tokens (e.g. because of an error).
8109+
// Skip through until we reach the 'end of directive' token.
8110+
while (Tok.isNot(tok::eof))
8111+
ConsumeAnyToken();
8112+
8113+
// Consume the end token.
8114+
if (Tok.is(tok::eof) && Tok.getEofData() == TypeStr.data())
8115+
ConsumeAnyToken();
8116+
return Result;
8117+
}
8118+
80548119
void Parser::DiagnoseBitIntUse(const Token &Tok) {
80558120
// If the token is for _ExtInt, diagnose it as being deprecated. Otherwise,
80568121
// the token is about _BitInt and gets (potentially) diagnosed as use of an

clang/lib/Parse/Parser.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
7070
PP.addCommentHandler(CommentSemaHandler.get());
7171

7272
PP.setCodeCompletionHandler(*this);
73+
74+
Actions.ParseTypeFromStringCallback =
75+
[this](StringRef TypeStr, StringRef Context, SourceLocation IncludeLoc) {
76+
return this->ParseTypeFromString(TypeStr, Context, IncludeLoc);
77+
};
7378
}
7479

7580
DiagnosticBuilder Parser::Diag(SourceLocation Loc, unsigned DiagID) {

0 commit comments

Comments
 (0)