diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index f04c220d6e1dbe..655bfcd66e970d 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -7467,6 +7467,10 @@ def ast_dump_filter : Separate<["-"], "ast-dump-filter">, MarshallingInfoString>; def ast_dump_filter_EQ : Joined<["-"], "ast-dump-filter=">, Alias; +def fdump_auto_type_inference : Flag<["-"], "fdump-auto-type-inference">, Group, + HelpText<"Dump auto type inference information">; +def fno_dump_auto_type_inference : Flag<["-"], "fno-dump-auto-type-inference">,Group, + HelpText<"Disable dumping auto type inference information">; def fno_modules_global_index : Flag<["-"], "fno-modules-global-index">, HelpText<"Do not automatically generate or update the global module index">, MarshallingInfoNegativeFlag>; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4d4579fcfd456b..502ef30fe5a21d 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -70,6 +70,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/TinyPtrVector.h" +#include "llvm/Support/CommandLine.h" #include #include #include @@ -77,6 +78,11 @@ #include #include +namespace opts { +// Option for dumping auto type inference +extern llvm::cl::OptionCategory DumpAutoInference; +extern llvm::cl::opt DumpAutoTypeInference; +} // namespace opts namespace llvm { class APSInt; template class DenseSet; @@ -560,6 +566,12 @@ class Sema final : public SemaBase { /// Warn that the stack is nearly exhausted. void warnStackExhausted(SourceLocation Loc); + /// Emits diagnostic remark indicating the compiler-deduced types and return + /// type for variables and functions + void DumpAutoTypeInference(SourceManager &SM, SourceLocation Loc, bool isVar, + ASTContext &Context, llvm::StringRef Name, + QualType DeducedType); + /// Run some code with "sufficient" stack space. (Currently, at least 256K is /// guaranteed). Produces a warning if we're low on stack space and allocates /// more in that case. Use this in code that may recurse deeply (for example, diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index a612dcd4b4d031..13d137ec0e784b 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -80,6 +80,14 @@ using namespace clang; using namespace sema; +namespace opts { +llvm::cl::OptionCategory DumpAutoInference("DumpAutoInference"); +llvm::cl::opt DumpAutoTypeInference{ + "fdump-auto-type-inference", + llvm::cl::desc("Dump compiler-deduced type for variables and return expressions declared using C++ 'auto' keyword"), llvm::cl::ZeroOrMore, + llvm::cl::cat(DumpAutoInference)}; +} // namespace opts + SourceLocation Sema::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) { return Lexer::getLocForEndOfToken(Loc, Offset, SourceMgr, LangOpts); } @@ -553,6 +561,23 @@ void Sema::warnStackExhausted(SourceLocation Loc) { } } +// Emits diagnostic remark indicating the compiler-deduced types and return type +// for variables and functions +void Sema::DumpAutoTypeInference(SourceManager &SM, SourceLocation Loc, + bool isVar, ASTContext &Context, + llvm::StringRef Name, QualType DeducedType) { + if (SM.isWrittenInMainFile(Loc) && + opts::DumpAutoTypeInference.getNumOccurrences()) { + DiagnosticsEngine &Diag = Context.getDiagnostics(); + unsigned DiagID = isVar ? Diag.getCustomDiagID(DiagnosticsEngine::Remark, + "type of '%0' deduced as %1") + : Diag.getCustomDiagID( + DiagnosticsEngine::Remark, + "return type of function '%0' deduced as %1"); + Diag.Report(Loc, DiagID) << Name << DeducedType; + } +} + void Sema::runWithSufficientStackSpace(SourceLocation Loc, llvm::function_ref Fn) { clang::runWithSufficientStackSpace([&] { warnStackExhausted(Loc); }, Fn); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 4b9b735f1cfb43..ba5cf1868384e2 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13148,6 +13148,12 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit, VDecl->setType(DeducedType); assert(VDecl->isLinkageValid()); + // Emit a remark indicating the compiler-deduced type for variables declared + // using the C++ 'auto' keyword + SourceManager &SM = getSourceManager(); + Sema::DumpAutoTypeInference(SM, VDecl->getLocation(), true, Context, + VDecl->getNameAsString(), DeducedType); + // In ARC, infer lifetime. if (getLangOpts().ObjCAutoRefCount && ObjC().inferObjCARCLifetime(VDecl)) VDecl->setInvalidDecl(); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 57465d4a77ac29..e14f86f2450cd7 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -3799,6 +3799,12 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, // Update all declarations of the function to have the deduced return type. Context.adjustDeducedFunctionResultType(FD, Deduced); + // Emit a remark indicating the compiler-deduced return type for functions + // declared using the C++ 'auto' keyword + SourceManager &SM = getSourceManager(); + Sema::DumpAutoTypeInference(SM, FD->getLocation(), false, Context, + FD->getNameAsString(), Deduced); + return false; } diff --git a/clang/test/Sema/fdump_auto-type-inference.cpp b/clang/test/Sema/fdump_auto-type-inference.cpp new file mode 100644 index 00000000000000..0509933a0b4a81 --- /dev/null +++ b/clang/test/Sema/fdump_auto-type-inference.cpp @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -std=c++14 -mllvm -fdump-auto-type-inference %s + +void testAuto() { + // Test auto variables + auto x = 5; + auto y = 3.14; + + // Test auto return type of a lambda function + auto add = [](int a, double b) -> double { + return a + b; + }; + + // Expected remarks based on the compiler output + // expected-remark@-5 {{type of 'x' deduced as 'int'}} + // expected-remark@-4 {{type of 'y' deduced as 'double'}} + // expected-remark@-3 {{type of 'add' deduced as '(lambda at %s'}} +} + +int main() { + testAuto(); + // Testing auto variables + auto x = 5; // int + auto y = 3.14; // double + auto z = 'c'; // char + + // expected-remark@+1{{type of 'x' deduced as 'int'}} + // expected-remark@+1{{type of 'y' deduced as 'double'}} + // expected-remark@+1{{type of 'z' deduced as 'char'}} + + // Testing auto return type of a function + auto add = [](auto a, auto b) { + return a + b; + }; + + auto divide = [](auto a, auto b) -> decltype(a / b) { + return a / b; + }; + + struct Foo { + auto getVal() const { + return val; + } + int val = 42; + }; + + // expected-remark@+2{{type of 'add' deduced as '(lambda}} + // expected-remark@+1{{type of 'divide' deduced as '(lambda}} + // expected-remark@+1{{function return type of 'getVal' deduced as 'int'}} + + return 0; +}