Skip to content

Commit

Permalink
PR45239: Don't deallocate TemplateIdAnnotations if they might still be
Browse files Browse the repository at this point in the history
in the token stream.

Previously we deleted all template-id annotations at the end of each
top-level declaration. That doesn't work: we can do some lookahead and
form a template-id annotation, and then roll back that lookahead, parse,
and decide that we're missing a semicolon at the end of a top-level
declaration, before we reach the annotation token. In that situation,
we'd end up parsing the annotation token after deleting its associated
data, leading to various forms of badness.

We now only delete template-id annotations if the preprocessor can
assure us that there are no annotation tokens left in the token stream
(or if we're already at EOF). This lets us delete the annotation tokens
earlier in a lot of cases; we now clean them up at the end of each
statement and class member, not just after each top-level declaration.
This also permitted some simplification of the delay-parsed templates
cleanup code.
  • Loading branch information
zygoloid committed Apr 6, 2020
1 parent 97e57f3 commit 6163aa9
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 41 deletions.
6 changes: 6 additions & 0 deletions clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1562,6 +1562,12 @@ class Preprocessor {
void EnterAnnotationToken(SourceRange Range, tok::TokenKind Kind,
void *AnnotationVal);

/// Determine whether it's possible for a future call to Lex to produce an
/// annotation token created by a previous call to EnterAnnotationToken.
bool mightHavePendingAnnotationTokens() {
return CurLexerKind != CLK_Lexer;
}

/// Update the current token to represent the provided
/// identifier, in order to cache an action performed by typo correction.
void TypoCorrectToken(const Token &Tok) {
Expand Down
17 changes: 16 additions & 1 deletion clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,22 @@ class Parser : public CodeCompletionHandler {
/// top-level declaration is finished.
SmallVector<TemplateIdAnnotation *, 16> TemplateIds;

void MaybeDestroyTemplateIds() {
if (!TemplateIds.empty() &&
(Tok.is(tok::eof) || !PP.mightHavePendingAnnotationTokens()))
DestroyTemplateIds();
}
void DestroyTemplateIds();

/// RAII object to destroy TemplateIdAnnotations where possible, from a
/// likely-good position during parsing.
struct DestroyTemplateIdAnnotationsRAIIObj {
Parser &Self;

DestroyTemplateIdAnnotationsRAIIObj(Parser &Self) : Self(Self) {}
~DestroyTemplateIdAnnotationsRAIIObj() { Self.MaybeDestroyTemplateIds(); }
};

/// Identifiers which have been declared within a tentative parse.
SmallVector<IdentifierInfo *, 8> TentativelyDeclaredIdentifiers;

Expand Down Expand Up @@ -1466,7 +1482,6 @@ class Parser : public CodeCompletionHandler {
void ParseLateTemplatedFuncDef(LateParsedTemplate &LPT);

static void LateTemplateParserCallback(void *P, LateParsedTemplate &LPT);
static void LateTemplateParserCleanupCallback(void *P);

Sema::ParsingClassState
PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface);
Expand Down
20 changes: 0 additions & 20 deletions clang/include/clang/Parse/RAIIObjectsForParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -459,26 +459,6 @@ namespace clang {
}
void skipToEnd();
};

/// RAIIObject to destroy the contents of a SmallVector of
/// TemplateIdAnnotation pointers and clear the vector.
class DestroyTemplateIdAnnotationsRAIIObj {
SmallVectorImpl<TemplateIdAnnotation *> &Container;

public:
DestroyTemplateIdAnnotationsRAIIObj(
SmallVectorImpl<TemplateIdAnnotation *> &Container)
: Container(Container) {}

~DestroyTemplateIdAnnotationsRAIIObj() {
for (SmallVectorImpl<TemplateIdAnnotation *>::iterator I =
Container.begin(),
E = Container.end();
I != E; ++I)
(*I)->Destroy();
Container.clear();
}
};
} // end namespace clang

#endif
1 change: 1 addition & 0 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3339,6 +3339,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// Each iteration of this loop reads one member-declaration.
ParseCXXClassMemberDeclarationWithPragmas(
CurAS, AccessAttrs, static_cast<DeclSpec::TST>(TagType), TagDecl);
MaybeDestroyTemplateIds();
}
T.consumeClose();
} else {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,

StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
Stmts, StmtCtx, TrailingElseLoc, Attrs);
MaybeDestroyTemplateIds();

assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) &&
"attributes on empty statement");
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Parse/ParseTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1618,6 +1618,9 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
if (!LPT.D)
return;

// Destroy TemplateIdAnnotations when we're done, if possible.
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this);

// Get the FunctionDecl.
FunctionDecl *FunD = LPT.D->getAsFunction();
// Track template parameter depth.
Expand Down
28 changes: 8 additions & 20 deletions clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,16 +433,7 @@ Parser::~Parser() {

PP.clearCodeCompletionHandler();

if (getLangOpts().DelayedTemplateParsing &&
!PP.isIncrementalProcessingEnabled() && !TemplateIds.empty()) {
// If an ASTConsumer parsed delay-parsed templates in their
// HandleTranslationUnit() method, TemplateIds created there were not
// guarded by a DestroyTemplateIdAnnotationsRAIIObj object in
// ParseTopLevelDecl(). Destroy them here.
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds);
}

assert(TemplateIds.empty() && "Still alive TemplateIdAnnotations around?");
DestroyTemplateIds();
}

/// Initialize - Warm up the parser.
Expand Down Expand Up @@ -538,11 +529,10 @@ void Parser::Initialize() {
ConsumeToken();
}

void Parser::LateTemplateParserCleanupCallback(void *P) {
// While this RAII helper doesn't bracket any actual work, the destructor will
// clean up annotations that were created during ActOnEndOfTranslationUnit
// when incremental processing is enabled.
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(((Parser *)P)->TemplateIds);
void Parser::DestroyTemplateIds() {
for (TemplateIdAnnotation *Id : TemplateIds)
Id->Destroy();
TemplateIds.clear();
}

/// Parse the first top-level declaration in a translation unit.
Expand Down Expand Up @@ -577,7 +567,7 @@ bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) {
/// declaration
/// [C++20] module-import-declaration
bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds);
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this);

// Skip over the EOF token, flagging end of previous input for incremental
// processing
Expand Down Expand Up @@ -663,9 +653,7 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {

// Late template parsing can begin.
if (getLangOpts().DelayedTemplateParsing)
Actions.SetLateTemplateParser(LateTemplateParserCallback,
PP.isIncrementalProcessingEnabled() ?
LateTemplateParserCleanupCallback : nullptr,
Actions.SetLateTemplateParser(LateTemplateParserCallback, nullptr,
this);
if (!PP.isIncrementalProcessingEnabled())
Actions.ActOnEndOfTranslationUnit();
Expand Down Expand Up @@ -727,7 +715,7 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, bool IsFirstDecl) {
Parser::DeclGroupPtrTy
Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
ParsingDeclSpec *DS) {
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds);
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this);
ParenBraceBracketBalancer BalancerRAIIObj(*this);

if (PP.isCodeCompletionReached()) {
Expand Down
7 changes: 7 additions & 0 deletions clang/test/Parser/cxx-template-decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,3 +279,10 @@ namespace NoCrashOnEmptyNestedNameSpecifier {
typename T = typename ABC<FnT>::template arg_t<0>> // expected-error {{no template named 'ABC'}}
void foo(FnT) {}
}

namespace PR45239 {
// Ensure we don't crash here. We used to deallocate the TemplateIdAnnotation
// before we'd parsed it.
template<int> int b;
template<int> auto f() -> b<0>; // expected-error +{{}}
}

0 comments on commit 6163aa9

Please sign in to comment.