Skip to content

Commit

Permalink
Use unique_ptr for cached tokens for default arguments in C++.
Browse files Browse the repository at this point in the history
Summary:
This changes pointers to cached tokens for default arguments in C++ from raw pointers to unique_ptrs.  There was a fixme in the code where the cached tokens are created  about using a smart pointer.

The change is straightforward, though I did have to track down and fix a memory corruption caused by the change.  memcpy was being used to copy parameter information.  This duplicated the unique_ptr, which led to the cached token buffer being deleted prematurely.

Patch by David Tarditi!

Reviewers: malcolm.parsons

Subscribers: arphaman, malcolm.parsons, cfe-commits

Differential Revision: https://reviews.llvm.org/D26435

llvm-svn: 287241
  • Loading branch information
pepsiman committed Nov 17, 2016
1 parent 97ff767 commit ff0382c
Show file tree
Hide file tree
Showing 7 changed files with 24 additions and 26 deletions.
6 changes: 3 additions & 3 deletions clang/include/clang/Parse/Parser.h
Expand Up @@ -1017,8 +1017,8 @@ class Parser : public CodeCompletionHandler {
/// (C++ [class.mem]p2).
struct LateParsedDefaultArgument {
explicit LateParsedDefaultArgument(Decl *P,
CachedTokens *Toks = nullptr)
: Param(P), Toks(Toks) { }
std::unique_ptr<CachedTokens> Toks = nullptr)
: Param(P), Toks(std::move(Toks)) { }

/// Param - The parameter declaration for this parameter.
Decl *Param;
Expand All @@ -1027,7 +1027,7 @@ class Parser : public CodeCompletionHandler {
/// argument expression, not including the '=' or the terminating
/// ')' or ','. This will be NULL for parameters that have no
/// default argument.
CachedTokens *Toks;
std::unique_ptr<CachedTokens> Toks;
};

/// LateParsedMethodDeclaration - A method declaration inside a class that
Expand Down
12 changes: 5 additions & 7 deletions clang/include/clang/Sema/DeclSpec.h
Expand Up @@ -1188,14 +1188,14 @@ struct DeclaratorChunk {
/// declaration of a member function), it will be stored here as a
/// sequence of tokens to be parsed once the class definition is
/// complete. Non-NULL indicates that there is a default argument.
CachedTokens *DefaultArgTokens;
std::unique_ptr<CachedTokens> DefaultArgTokens;

ParamInfo() = default;
ParamInfo(IdentifierInfo *ident, SourceLocation iloc,
Decl *param,
CachedTokens *DefArgTokens = nullptr)
std::unique_ptr<CachedTokens> DefArgTokens = nullptr)
: Ident(ident), IdentLoc(iloc), Param(param),
DefaultArgTokens(DefArgTokens) {}
DefaultArgTokens(std::move(DefArgTokens)) {}
};

struct TypeAndRange {
Expand Down Expand Up @@ -1310,10 +1310,8 @@ struct DeclaratorChunk {
///
/// This is used in various places for error recovery.
void freeParams() {
for (unsigned I = 0; I < NumParams; ++I) {
delete Params[I].DefaultArgTokens;
Params[I].DefaultArgTokens = nullptr;
}
for (unsigned I = 0; I < NumParams; ++I)
Params[I].DefaultArgTokens.reset();
if (DeleteParams) {
delete[] Params;
DeleteParams = false;
Expand Down
6 changes: 2 additions & 4 deletions clang/lib/Parse/ParseCXXInlineMethods.cpp
Expand Up @@ -319,7 +319,8 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
// Introduce the parameter into scope.
bool HasUnparsed = Param->hasUnparsedDefaultArg();
Actions.ActOnDelayedCXXMethodParameter(getCurScope(), Param);
if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {
std::unique_ptr<CachedTokens> Toks = std::move(LM.DefaultArgs[I].Toks);
if (Toks) {
// Mark the end of the default argument so that we know when to stop when
// we parse it later on.
Token LastDefaultArgToken = Toks->back();
Expand Down Expand Up @@ -377,9 +378,6 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {

if (Tok.is(tok::eof) && Tok.getEofData() == Param)
ConsumeAnyToken();

delete Toks;
LM.DefaultArgs[I].Toks = nullptr;
} else if (HasUnparsed) {
assert(Param->hasInheritedDefaultArg());
FunctionDecl *Old = cast<FunctionDecl>(LM.Method)->getPreviousDecl();
Expand Down
10 changes: 4 additions & 6 deletions clang/lib/Parse/ParseDecl.cpp
Expand Up @@ -6022,7 +6022,7 @@ void Parser::ParseParameterDeclarationClause(

// DefArgToks is used when the parsing of default arguments needs
// to be delayed.
CachedTokens *DefArgToks = nullptr;
std::unique_ptr<CachedTokens> DefArgToks;

// If no parameter was specified, verify that *something* was specified,
// otherwise we have a missing type and identifier.
Expand Down Expand Up @@ -6058,13 +6058,11 @@ void Parser::ParseParameterDeclarationClause(
// If we're inside a class definition, cache the tokens
// corresponding to the default argument. We'll actually parse
// them when we see the end of the class definition.
// FIXME: Can we use a smart pointer for Toks?
DefArgToks = new CachedTokens;
DefArgToks.reset(new CachedTokens);

SourceLocation ArgStartLoc = NextToken().getLocation();
if (!ConsumeAndStoreInitializer(*DefArgToks, CIK_DefaultArgument)) {
delete DefArgToks;
DefArgToks = nullptr;
DefArgToks.reset();
Actions.ActOnParamDefaultArgumentError(Param, EqualLoc);
} else {
Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc,
Expand Down Expand Up @@ -6100,7 +6098,7 @@ void Parser::ParseParameterDeclarationClause(

ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
ParmDeclarator.getIdentifierLoc(),
Param, DefArgToks));
Param, std::move(DefArgToks)));
}

if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/ParseDeclCXX.cpp
Expand Up @@ -2039,7 +2039,7 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
LateMethod->DefaultArgs.reserve(FTI.NumParams);
for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx)
LateMethod->DefaultArgs.push_back(LateParsedDefaultArgument(
FTI.Params[ParamIdx].Param, FTI.Params[ParamIdx].DefaultArgTokens));
FTI.Params[ParamIdx].Param, std::move(FTI.Params[ParamIdx].DefaultArgTokens)));
}
}

Expand Down
10 changes: 8 additions & 2 deletions clang/lib/Sema/DeclSpec.cpp
Expand Up @@ -223,13 +223,19 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
if (!TheDeclarator.InlineStorageUsed &&
NumParams <= llvm::array_lengthof(TheDeclarator.InlineParams)) {
I.Fun.Params = TheDeclarator.InlineParams;
// Zero the memory block so that unique pointers are initialized
// properly.
memset(I.Fun.Params, 0, sizeof(Params[0]) * NumParams);
I.Fun.DeleteParams = false;
TheDeclarator.InlineStorageUsed = true;
} else {
I.Fun.Params = new DeclaratorChunk::ParamInfo[NumParams];
// Call the version of new that zeroes memory so that unique pointers
// are initialized properly.
I.Fun.Params = new DeclaratorChunk::ParamInfo[NumParams]();
I.Fun.DeleteParams = true;
}
memcpy(I.Fun.Params, Params, sizeof(Params[0]) * NumParams);
for (unsigned i = 0; i < NumParams; i++)
I.Fun.Params[i] = std::move(Params[i]);
}

// Check what exception specification information we should actually store.
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Sema/SemaDeclCXX.cpp
Expand Up @@ -395,7 +395,7 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
++argIdx) {
ParmVarDecl *Param = cast<ParmVarDecl>(chunk.Fun.Params[argIdx].Param);
if (Param->hasUnparsedDefaultArg()) {
CachedTokens *Toks = chunk.Fun.Params[argIdx].DefaultArgTokens;
std::unique_ptr<CachedTokens> Toks = std::move(chunk.Fun.Params[argIdx].DefaultArgTokens);
SourceRange SR;
if (Toks->size() > 1)
SR = SourceRange((*Toks)[1].getLocation(),
Expand All @@ -404,8 +404,6 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
SR = UnparsedDefaultArgLocs[Param];
Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
<< SR;
delete Toks;
chunk.Fun.Params[argIdx].DefaultArgTokens = nullptr;
} else if (Param->getDefaultArg()) {
Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
<< Param->getDefaultArg()->getSourceRange();
Expand Down

0 comments on commit ff0382c

Please sign in to comment.