Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -1071,3 +1071,16 @@ def CTADMaybeUnsupported : DiagGroup<"ctad-maybe-unsupported">; def FortifySource : DiagGroup<"fortify-source">; +// Frontend insight remarks. + +def SpecialMemberGeneration : DiagGroup<"special-member-generated">; +def NameResolution : DiagGroup<"name-resolution">; +def DefaultValue : DiagGroup<"default-value">; +def ImplicitConversion : DiagGroup<"implicit-conversion">; + +def InsightRemarks : DiagGroup<"insight", [ + SpecialMemberGeneration, + NameResolution, + DefaultValue, + ImplicitConversion +]>; Index: clang/include/clang/Basic/DiagnosticIDs.h =================================================================== --- clang/include/clang/Basic/DiagnosticIDs.h +++ clang/include/clang/Basic/DiagnosticIDs.h @@ -302,7 +302,6 @@ /// given group name. static StringRef getNearestOption(diag::Flavor Flavor, StringRef Group); -private: /// Classify the specified diagnostic ID into a Level, consumable by /// the DiagnosticClient. /// @@ -315,6 +314,7 @@ getDiagnosticLevel(unsigned DiagID, SourceLocation Loc, const DiagnosticsEngine &Diag) const LLVM_READONLY; +private: diag::Severity getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc, const DiagnosticsEngine &Diag) const LLVM_READONLY; Index: clang/include/clang/Basic/DiagnosticOptions.h =================================================================== --- clang/include/clang/Basic/DiagnosticOptions.h +++ clang/include/clang/Basic/DiagnosticOptions.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_BASIC_DIAGNOSTICOPTIONS_H #include "clang/Basic/LLVM.h" +#include "clang/Frontend/CommandLineSourceLoc.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include #include @@ -102,6 +103,9 @@ /// prefixes removed. std::vector Remarks; + /// Code range for which insight remarks shall be produced. + llvm::Optional InsightRemarksRange; + /// The prefixes for comment directives sought by -verify ("expected" by /// default). std::vector VerifyPrefixes; Index: clang/include/clang/Basic/DiagnosticOptions.def =================================================================== --- clang/include/clang/Basic/DiagnosticOptions.def +++ clang/include/clang/Basic/DiagnosticOptions.def @@ -51,6 +51,7 @@ DIAGOPT(ShowLocation, 1, 1) /// Show source location information. DIAGOPT(AbsolutePath, 1, 0) /// Use absolute paths. DIAGOPT(ShowCarets, 1, 1) /// Show carets in diagnostics. +DIAGOPT(HideContextStack, 1, 0) /// Suppress context stack printing. DIAGOPT(ShowFixits, 1, 1) /// Show fixit information. DIAGOPT(ShowSourceRanges, 1, 0) /// Show source ranges in numeric form. DIAGOPT(ShowParseableFixits, 1, 0) /// Show machine parseable fix-its. Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9755,4 +9755,35 @@ "__builtin_bit_cast %select{source|destination}0 type must be trivially copyable">; def err_bit_cast_type_size_mismatch : Error< "__builtin_bit_cast source size does not equal destination size (%0 vs %1)">; +// InsightRemarks +def remark_implicit_default_ctor_generated : Remark< + "implicit default constructor was generated for class %0">, + InGroup; +def remark_implicit_copy_ctor_generated : Remark< + "implicit copy constructor was generated for class %0">, + InGroup; +def remark_implicit_move_ctor_generated : Remark< + "implicit move constructor was generated for class %0">, + InGroup; +def remark_implicit_copy_assignment_generated : Remark< + "implicit copy assignment operator was generated for class %0">, + InGroup; +def remark_implicit_move_assignment_generated : Remark< + "implicit move assignment operator was generated for class %0">, + InGroup; +def remark_implicit_dtor_generated : Remark< + "implicit destructor was generated for class %0">, + InGroup; + +def remark_function_overload_considered_in_resolution : Remark< + "%0 %1 of signature %2 considered in resolution of %3">, + InGroup; + +def remark_default_template_argument : Remark< + "default value %0 used for %1 argument %2 in instantiation of template %3">, + InGroup; + +def remark_using_implicit_conversion : Remark< + "using implicit conversion from %0 to %1">, + InGroup; } // end of sema component. Index: clang/include/clang/Driver/CC1Options.td =================================================================== --- clang/include/clang/Driver/CC1Options.td +++ clang/include/clang/Driver/CC1Options.td @@ -459,6 +459,13 @@ def Wno_rewrite_macros : Flag<["-"], "Wno-rewrite-macros">, HelpText<"Silence ObjC rewriting warnings">; +def insight_remarks_range : Flag<["-"], "insight-remarks-range">, + MetaVarName<"::-:">, + HelpText<"Print insight remarks only for given range.">; +def insight_remarks_range_EQ : Joined<["-"], "insight-remarks-range=">, + Alias; + + //===----------------------------------------------------------------------===// // Frontend Options //===----------------------------------------------------------------------===// Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -1577,6 +1577,14 @@ addDiagnosticArgs(Args, OPT_W_Group, OPT_W_value_Group, Opts.Warnings); addDiagnosticArgs(Args, OPT_R_Group, OPT_R_value_Group, Opts.Remarks); + if (const Arg *A = Args.getLastArg(OPT_insight_remarks_range)) { + Opts.InsightRemarksRange = ParsedSourceRange::fromString(A->getValue()); + if (Opts.InsightRemarksRange && + Opts.InsightRemarksRange.getValue().FileName.empty()) + Diags->Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(); + } + return Success; } Index: clang/lib/Sema/CMakeLists.txt =================================================================== --- clang/lib/Sema/CMakeLists.txt +++ clang/lib/Sema/CMakeLists.txt @@ -20,6 +20,7 @@ DeclSpec.cpp DelayedDiagnostic.cpp IdentifierResolver.cpp + InsightRemarks.cpp JumpDiagnostics.cpp MultiplexExternalSemaSource.cpp ParsedAttr.cpp Index: clang/lib/Sema/InsightRemarks.h =================================================================== --- /dev/null +++ clang/lib/Sema/InsightRemarks.h @@ -0,0 +1,36 @@ +//===--- InsightRemarks.h - Utilities for insight remarks -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains utilities for insight remarks. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_SEMA_INSIGHTREMARKS_H +#define LLVM_CLANG_LIB_SEMA_INSIGHTREMARKS_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/CommandLineSourceLoc.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/Optional.h" + +namespace clang { + +bool isInsideInsightRange( + const SourceManager &SM, const SourceLocation &Loc, + const llvm::Optional &InsightRemarksRange); + +/// Prints insight remark if Loc is within InsightRange +void printInsightRemark( + Sema &S, SourceLocation Loc, unsigned DiagID, + std::function RemarkProducer); + +} // namespace clang + +#endif Index: clang/lib/Sema/InsightRemarks.cpp =================================================================== --- /dev/null +++ clang/lib/Sema/InsightRemarks.cpp @@ -0,0 +1,71 @@ +//===--- InsightRemarks.cpp - Utilities for insight remarks -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains utilities for insight remarks. +// +//===----------------------------------------------------------------------===// + +#include "InsightRemarks.h" +#include "llvm/ADT/StringRef.h" +#include + +namespace clang { + +inline bool isInsideInsightRange( + const SourceManager &SM, const SourceLocation &Loc, + const llvm::Optional &InsightRemarksRange) { + if (!InsightRemarksRange) // Range is not set ==> output insight remarks + // everywhere + return true; + + const auto &Range = InsightRemarksRange.getValue(); + assert(!Range.FileName.empty() && "FileName is not set"); + + const std::pair DecLoc = SM.getDecomposedLoc(Loc); + StringRef Filename = SM.getFilename(Loc); + const std::size_t LineNum = SM.getLineNumber(DecLoc.first, DecLoc.second); + const std::size_t ColumnNum = SM.getColumnNumber(DecLoc.first, DecLoc.second); + + return Filename == Range.FileName + // Loc is NOT OUTSIDE of the Range + && + !(LineNum < Range.Begin.first || LineNum > Range.End.first || + (LineNum == Range.Begin.first && ColumnNum < Range.Begin.second) || + (LineNum == Range.End.first && ColumnNum > Range.End.second)); +}; + +/// Prints insight remark if Loc is within InsightRange +void printInsightRemark( + Sema &S, SourceLocation Loc, unsigned DiagID, + std::function RemarkProducer) { + if (S.Diags.getDiagnosticIDs()->getDiagnosticLevel( + DiagID, SourceLocation(), S.Diags) != DiagnosticIDs::Level::Ignored && + isInsideInsightRange( + S.getSourceManager(), Loc, + S.Diags.getDiagnosticOptions().InsightRemarksRange)) { + // Turn off caret and context printing for the remark and restore + // afterwards. + const bool ShowCarets = S.Diags.getDiagnosticOptions().ShowCarets; + const bool HideContextStack = + S.Diags.getDiagnosticOptions().HideContextStack; + + S.Diags.getDiagnosticOptions().ShowCarets = false; + S.Diags.getDiagnosticOptions().HideContextStack = true; + { + auto DiagBuilder = S.Diag(Loc, DiagID); + RemarkProducer(DiagBuilder); + // Destructor of DiagBuilder triggers diagnostics emitting. + // Need to finish that before diag options are restored. + } + S.Diags.getDiagnosticOptions().ShowCarets = ShowCarets; + S.Diags.getDiagnosticOptions().HideContextStack = HideContextStack; + } +} + +} // namespace clang \ No newline at end of file Index: clang/lib/Sema/Sema.cpp =================================================================== --- clang/lib/Sema/Sema.cpp +++ clang/lib/Sema/Sema.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "InsightRemarks.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/DeclCXX.h" @@ -1348,7 +1349,8 @@ // that is different from the last template instantiation where // we emitted an error, print a template instantiation // backtrace. - if (!DiagnosticIDs::isBuiltinNote(DiagID)) + if (!DiagnosticIDs::isBuiltinNote(DiagID) && + !Diags.getDiagnosticOptions().HideContextStack) PrintContextStack(); } Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "InsightRemarks.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" @@ -11079,6 +11080,9 @@ PushOnScopeChains(DefaultCon, S, false); ClassDecl->addDecl(DefaultCon); + printInsightRemark(*this, DefaultCon->getLocation(), + diag::remark_implicit_default_ctor_generated, + [&](DiagnosticBuilder &db) { db << ClassDecl; }); return DefaultCon; } @@ -11358,6 +11362,10 @@ PushOnScopeChains(Destructor, S, false); ClassDecl->addDecl(Destructor); + printInsightRemark(*this, Destructor->getLocation(), + diag::remark_implicit_dtor_generated, + [&](DiagnosticBuilder &db) { db << ClassDecl; }); + return Destructor; } @@ -11963,6 +11971,10 @@ PushOnScopeChains(CopyAssignment, S, false); ClassDecl->addDecl(CopyAssignment); + printInsightRemark(*this, CopyAssignment->getLocation(), + diag::remark_implicit_copy_assignment_generated, + [&](DiagnosticBuilder &db) { db << ClassDecl; }); + return CopyAssignment; } @@ -12289,6 +12301,10 @@ PushOnScopeChains(MoveAssignment, S, false); ClassDecl->addDecl(MoveAssignment); + printInsightRemark(*this, MoveAssignment->getLocation(), + diag::remark_implicit_move_assignment_generated, + [&](DiagnosticBuilder &db) { db << ClassDecl; }); + return MoveAssignment; } @@ -12674,6 +12690,10 @@ PushOnScopeChains(CopyConstructor, S, false); ClassDecl->addDecl(CopyConstructor); + printInsightRemark(*this, CopyConstructor->getLocation(), + diag::remark_implicit_copy_ctor_generated, + [&](DiagnosticBuilder &db) { db << ClassDecl; }); + return CopyConstructor; } @@ -12806,6 +12826,10 @@ PushOnScopeChains(MoveConstructor, S, false); ClassDecl->addDecl(MoveConstructor); + printInsightRemark(*this, MoveConstructor->getLocation(), + diag::remark_implicit_move_ctor_generated, + [&](DiagnosticBuilder &db) { db << ClassDecl; }); + return MoveConstructor; } Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -11,7 +11,7 @@ /// //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" +#include "InsightRemarks.h" #include "TreeTransform.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTContext.h" @@ -33,6 +33,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaLambda.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/APInt.h" @@ -3900,6 +3901,11 @@ From, /*FIXME:ConstructLoc*/SourceLocation(), ConstructorArgs)) return ExprError(); + + printInsightRemark( + *this, From->getExprLoc(), diag::remark_default_template_argument, + [&](DiagnosticBuilder &db) { db << FromType << ToType; }); + return BuildCXXConstructExpr( /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.FoundCopyConstructor, SCS.CopyConstructor, Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ clang/lib/Sema/SemaInit.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "InsightRemarks.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" @@ -7484,6 +7485,7 @@ Entity.getType(); ExprResult CurInit((Expr *)nullptr); + ExprResult LastInit; SmallVector ArrayLoopCommonExprs; // For initialization steps that start with a single initializer, @@ -7560,6 +7562,7 @@ Step != StepEnd; ++Step) { if (CurInit.isInvalid()) return ExprError(); + LastInit = CurInit; QualType SourceType = CurInit.get() ? CurInit.get()->getType() : QualType(); @@ -8194,6 +8197,13 @@ break; } } + if (LastInit.isUsable() && LastInit.get()->getType() != Step->Type) { + printInsightRemark(S, Kind.getLocation(), + diag::remark_using_implicit_conversion, + [&](DiagnosticBuilder &db) { + db << LastInit.get()->getType() << Step->Type; + }); + } } // Check whether the initializer has a shorter lifetime than the initialized Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/Overload.h" +#include "InsightRemarks.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" @@ -24,6 +24,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Overload.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" @@ -12136,6 +12137,33 @@ if (CandidateSet->empty()) return false; + for (const auto &candidate : *CandidateSet) { + if (candidate.Function) { + + const char *func_kind = nullptr; + switch (candidate.Function->getTemplatedKind()) { + case FunctionDecl::TK_FunctionTemplate: + func_kind = "function template"; + break; + case FunctionDecl::TK_FunctionTemplateSpecialization: + case FunctionDecl::TK_MemberSpecialization: + case FunctionDecl::TK_DependentFunctionTemplateSpecialization: + func_kind = "function template specialization"; + break; + case FunctionDecl::TK_NonTemplate: + func_kind = "function"; + } + + printInsightRemark( + *this, Fn->getExprLoc(), + diag::remark_function_overload_considered_in_resolution, + [&](DiagnosticBuilder &db) { + db << func_kind << candidate.Function + << candidate.Function->getType() << Fn; + }); + } + } + UnbridgedCasts.restore(); return false; } Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -8,6 +8,7 @@ // This file implements semantic analysis for C++ templates. //===----------------------------------------------------------------------===// +#include "InsightRemarks.h" #include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -4632,6 +4633,13 @@ Param->getDefaultArgumentLoc(), Param->getDeclName()); } + printInsightRemark(SemaRef, TemplateLoc, + diag::remark_default_template_argument, + [&](DiagnosticBuilder &db) { + db << Param->getDefaultArgument() << "non-template type" + << Param << Template; + }); + return ArgType; } @@ -4678,6 +4686,12 @@ for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) TemplateArgLists.addOuterTemplateArguments(None); + printInsightRemark( + SemaRef, TemplateLoc, diag::remark_default_template_argument, + [&](DiagnosticBuilder &db) { + db << Param->getDefaultArgument() << "non-type" << Param << Template; + }); + EnterExpressionEvaluationContext ConstantEvaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists); @@ -4740,6 +4754,13 @@ return TemplateName(); } + printInsightRemark(SemaRef, TemplateLoc, + diag::remark_default_template_argument, + [&](DiagnosticBuilder &db) { + db << Param->getDefaultArgument().getArgument() + << "template type" << Param << Template; + }); + return SemaRef.SubstTemplateName( QualifierLoc, Param->getDefaultArgument().getArgument().getAsTemplate(), Index: clang/test/Frontend/insight-remarks-default-values.cpp =================================================================== --- /dev/null +++ clang/test/Frontend/insight-remarks-default-values.cpp @@ -0,0 +1,20 @@ +// RUN: %clang -cc1 -std=c++17 -Rdefault-value -fsyntax-only %s 2>&1 | FileCheck %s +template class foo { + T memfoo; +}; + +template class bar { + int n = N; +}; + +template typename C = foo> class baz { +}; + +int main() { + foo<> x; +// CHECK: remark: default value 'bool' used for non-template type argument 'T' in instantiation of template 'foo' + bar<> y; +// CHECK: remark: default value 42 used for non-type argument 'N' in instantiation of template 'bar' + baz<> z; +// CHECK: remark: default value 'foo' used for template type argument 'C' in instantiation of template 'baz' +} \ No newline at end of file Index: clang/test/Frontend/insight-remarks-implicit-conversion.cpp =================================================================== --- /dev/null +++ clang/test/Frontend/insight-remarks-implicit-conversion.cpp @@ -0,0 +1,74 @@ +// RUN: %clang -cc1 -Rimplicit-conversion -fsyntax-only %s 2>&1 | FileCheck %s + +void foof(bool) {} + +int main() { + { + struct foo { + operator int() { return 42; } + }; + + foo b; + int a = b; +// CHECK: remark: using implicit conversion from 'foo' to 'int' + } + { + int a = 3; + unsigned b = 4; +// CHECK: remark: using implicit conversion from 'int' to 'unsigned int' + unsigned long long c = a + b; +// CHECK: remark: using implicit conversion from 'unsigned int' to 'unsigned long long' + foof(a); +// CHECK: remark: using implicit conversion from 'int' to 'bool' + } + { + struct bar {}; + struct foo { + bar b; + operator bar() { return b; } +// CHECK: remark: using implicit conversion from 'bar' to 'const bar' + }; + foo f; + const bar& b = f; +// CHECK: remark: using implicit conversion from 'foo' to 'bar' +// CHECK: remark: using implicit conversion from 'bar' to 'const bar' + } + { + short a; + const unsigned short& b = a; +// CHECK: remark: using implicit conversion from 'short' to 'const unsigned short' + } + { + struct foo { + static void bar(const int&){} + }; + int a = 3; + foo::bar(a); +// CHECK: remark: using implicit conversion from 'int' to 'const int' + } + { + struct foo {}; + struct bar : foo {}; + struct local { static void f(const foo &) {} }; + bar b; + local::f(b); +// CHECK: remark: using implicit conversion from 'bar' to 'const bar' +// CHECK: remark: using implicit conversion from 'const bar' to 'const foo' + } + { + char a[5]; + + const char* b = a; +// CHECK: remark: using implicit conversion from 'char [5]' to 'const char *' + + struct local { static void foo(const char*) {} }; + local::foo(a); +// CHECK: remark: using implicit conversion from 'char [5]' to 'const char *' + } + { + long a = 5; + if(a) + a = 7; +// CHECK: remark: using implicit conversion from 'int' to 'long' + } +} \ No newline at end of file Index: clang/test/Frontend/insight-remarks-overloaded-function.cpp =================================================================== --- /dev/null +++ clang/test/Frontend/insight-remarks-overloaded-function.cpp @@ -0,0 +1,22 @@ +// RUN: %clang -cc1 -Rname-resolution -fsyntax-only %s 2>&1 | FileCheck %s + +namespace { + void foo() {} +} +void foo(int) {} +void foo(int*) {} + +template void foo(T) { } + +int main() { + foo(); +// CHECK: remark: function template 'foo' of signature 'void (T)' considered in resolution of foo +// CHECK: remark: function 'foo' of signature 'void (int *)' considered in resolution of foo +// CHECK: remark: function 'foo' of signature 'void (int)' considered in resolution of foo +// CHECK: remark: function 'foo' of signature 'void ()' considered in resolution of foo + foo(5); +// CHECK: remark: function template specialization 'foo' of signature 'void (int)' considered in resolution of foo +// CHECK: remark: function 'foo' of signature 'void (int *)' considered in resolution of foo +// CHECK: remark: function 'foo' of signature 'void (int)' considered in resolution of foo +// CHECK: remark: function 'foo' of signature 'void ()' considered in resolution of foo +} Index: clang/test/Frontend/insight-remarks-range.cpp =================================================================== --- /dev/null +++ clang/test/Frontend/insight-remarks-range.cpp @@ -0,0 +1,14 @@ +// RUN: %clang -cc1 -Rinsight -insight-remarks-range=%s:4:16-4:32 -fsyntax-only %s 2>&1 | FileCheck %s + +class hay1 {}; +class hay2 {}; class needle {}; class hay3 {}; +// CHECK: needle +class hay4 {}; + +int main() { + hay1 h1; + hay2 h2; + hay3 h3; + hay4 h4; + needle n; +} \ No newline at end of file Index: clang/test/Frontend/insight-remarks-special-members-generated.cpp =================================================================== --- /dev/null +++ clang/test/Frontend/insight-remarks-special-members-generated.cpp @@ -0,0 +1,12 @@ +// RUN: %clang -cc1 -Rspecial-member-generated -fsyntax-only %s 2>&1 | FileCheck %s + +class foo { +// CHECK: remark: implicit default constructor was generated for class 'foo' +// CHECK: remark: implicit copy constructor was generated for class 'foo' +// CHECK: remark: implicit move constructor was generated for class 'foo' + int a; +}; + +int main() { + foo x; +} \ No newline at end of file