Fix crashes from delayed template parsing code that assumed getBody() would return non-null.

Patch by Etienne Bergeron.

llvm-svn: 264049
This commit is contained in:
Aaron Ballman 2016-03-22 13:37:44 +00:00
parent 26d239c293
commit 73a7bd3616
4 changed files with 71 additions and 8 deletions

View File

@ -0,0 +1,32 @@
// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -fdelayed-template-parsing
template<class T>
struct PositiveFieldBeforeConstructor {
PositiveFieldBeforeConstructor() {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G, H
int F;
bool G /* with comment */;
int *H;
};
// Explicit instantiation.
template class PositiveFieldBeforeConstructor<int>;
template<class T>
struct PositiveFieldAfterConstructor {
PositiveFieldAfterConstructor() {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G, H
int F;
bool G /* with comment */;
int *H;
};
// Explicit instantiation.
template class PositiveFieldAfterConstructor<int>;
// This declaration isn't used and won't be parsed 'delayed-template-parsing'.
// The body of the declaration is 'null' and may cause crash if not handled
// properly by checkers.
template<class T>
struct UnusedDelayedConstructor {
UnusedDelayedConstructor() {}
int F;
};

View File

@ -179,6 +179,11 @@ void ProTypeMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
const auto &MemberFields = Ctor->getParent()->fields();
// Skip declarations delayed by late template parsing without a body.
const Stmt *Body = Ctor->getBody();
if (!Body)
return;
SmallPtrSet<const FieldDecl *, 16> FieldsToInit;
fieldsRequiringInit(MemberFields, FieldsToInit);
if (FieldsToInit.empty())
@ -193,8 +198,8 @@ void ProTypeMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
continue;
FieldsToInit.erase(Init->getMember());
}
removeFieldsInitializedInBody(*Ctor->getBody(), *Result.Context,
FieldsToInit);
removeFieldsInitializedInBody(*Body, *Result.Context, FieldsToInit);
if (FieldsToInit.empty())
return;

View File

@ -0,0 +1,28 @@
// RUN: %check_clang_tidy %s modernize-redundant-void-arg %t -- -- -fdelayed-template-parsing
int foo(void) {
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
// CHECK-FIXES: {{^}}int foo() {{{$}}
return 0;
}
template <class T>
struct MyFoo {
int foo(void) {
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
// CHECK-FIXES: {{^}} int foo() {{{$}}
return 0;
}
};
// Explicit instantiation.
template class MyFoo<int>;
template <class T>
struct MyBar {
// This declaration isn't instantiated and won't be parsed 'delayed-template-parsing'.
int foo(void) {
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
// CHECK-FIXES: {{^}} int foo() {{{$}}
return 0;
}
};

View File

@ -102,13 +102,11 @@ void RedundantVoidArgCheck::check(const MatchFinder::MatchResult &Result) {
void RedundantVoidArgCheck::processFunctionDecl(
const MatchFinder::MatchResult &Result, const FunctionDecl *Function) {
SourceLocation Start = Function->getLocStart();
if (Function->isThisDeclarationADefinition()) {
SourceLocation End;
if (Function->hasBody())
End = Function->getBody()->getLocStart().getLocWithOffset(-1);
else
End = Function->getLocEnd();
const Stmt *Body = Function->getBody();
SourceLocation Start = Function->getLocStart();
SourceLocation End = Body ? Body->getLocStart().getLocWithOffset(-1) :
Function->getLocEnd();
removeVoidArgumentTokens(Result, SourceRange(Start, End),
"function definition");
} else {