From 73a7bd3616d8ae6788256ce8fe8c5dcc351e9ecc Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Tue, 22 Mar 2016 13:37:44 +0000 Subject: Fix crashes from delayed template parsing code that assumed getBody() would return non-null. Patch by Etienne Bergeron. llvm-svn: 264049 --- ...coreguidelines-pro-type-member-init-delayed.cpp | 32 ++++++++++++++++++++++ .../cppcoreguidelines/ProTypeMemberInitCheck.cpp | 9 ++++-- .../modernize-redundant-void-arg-delayed.cpp | 28 +++++++++++++++++++ .../clang-tidy/modernize/RedundantVoidArgCheck.cpp | 10 +++---- 4 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 clang-tools-extra/clang-tidy/cppcoreguidelines-pro-type-member-init-delayed.cpp create mode 100644 clang-tools-extra/clang-tidy/modernize-redundant-void-arg-delayed.cpp (limited to 'clang-tools-extra/clang-tidy') diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines-pro-type-member-init-delayed.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines-pro-type-member-init-delayed.cpp new file mode 100644 index 00000000000..356aa0072fd --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines-pro-type-member-init-delayed.cpp @@ -0,0 +1,32 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -fdelayed-template-parsing + +template +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; + +template +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; + +// 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 +struct UnusedDelayedConstructor { + UnusedDelayedConstructor() {} + int F; +}; diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp index 6e5896a9f49..672d222e595 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp @@ -179,6 +179,11 @@ void ProTypeMemberInitCheck::check(const MatchFinder::MatchResult &Result) { const auto *Ctor = Result.Nodes.getNodeAs("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 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; diff --git a/clang-tools-extra/clang-tidy/modernize-redundant-void-arg-delayed.cpp b/clang-tools-extra/clang-tidy/modernize-redundant-void-arg-delayed.cpp new file mode 100644 index 00000000000..dd887758819 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize-redundant-void-arg-delayed.cpp @@ -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 +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; + +template +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; + } +}; diff --git a/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp b/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp index 4c8f681be0a..eb971a91d5c 100644 --- a/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp @@ -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 { -- cgit v1.2.3