[clang] [clang] Dump Auto Type Inference (PR #95509)

Nisarga V via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 13 23:25:44 PDT 2024


https://github.com/nisarga3 created https://github.com/llvm/llvm-project/pull/95509

This pull request introduces the functionality to dump type inferences for variables and function return types using the auto keyword in C++11. When the -fdump-auto-type-inference option is specified, the compiler will emit informational messages that describe the inferred types for auto declarations.
 
**Problem Statement :**
C++11's auto keyword allows developers to let the compiler deduce the type of a variable or the return type of a function, which simplifies code and reduces redundancy. However, this can sometimes obscure the actual types being used, making it difficult to understand the code's behaviour, especially in complex codebases or during debugging. Developers need a way to see the types inferred by the compiler to improve their understanding and confidence in the code.
 
**Proposed Solution**
The proposed solution is to implement a compiler feature that dumps the inferred types of variables and function return types when the -fdump-auto-type-inference option is used. This feature will output informational messages indicating the deduced types, providing clarity and aiding in debugging.
 
**Compilation Command (from build directory)**
 `./bin/clang++ -mllvm -fdump-auto-type-inference ./Hello.cpp`
 
Hello.cpp
```
#include<iostream>
using namespace std;
void testAuto() {
 auto w = 5;
 auto z = 3.14;
 
 auto add = [](auto a, auto b) {
   return a + b;
 };
}
int main() {
 testAuto();
 
   auto x = 5;            // int
   auto y = 3.14;         // double
   auto z = 'c';          // char
   auto arr = {1, 2, 3};  // std::initializer_list<int>
   
   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;
   };
       
   return 0;
}
```
 
Output

```
../hello.cpp:5:8: remark: type of 'w' deduced as 'int'
   5 |   auto w = 5;
     |        ^
../hello.cpp:6:8: remark: type of 'z' deduced as 'double'
   6 |   auto z = 3.14;
     |        ^
../hello.cpp:8:8: remark: type of 'add' deduced as '(lambda at ../hello.cpp:8:14)'
   8 |   auto add = [](auto a, auto b) {
     |        ^
../hello.cpp:16:10: remark: type of 'x' deduced as 'int'
  16 |     auto x = 5;            // int
     |          ^
../hello.cpp:17:10: remark: type of 'y' deduced as 'double'
  17 |     auto y = 3.14;         // double
     |          ^
../hello.cpp:18:10: remark: type of 'z' deduced as 'char'
  18 |     auto z = 'c';          // char
     |          ^
../hello.cpp:19:10: remark: type of 'arr' deduced as 'std::initializer_list<int>'
  19 |     auto arr = {1, 2, 3};  // std::initializer_list<int>
     |          ^
../hello.cpp:27:10: remark: type of 'add' deduced as '(lambda at ../hello.cpp:27:16)'
  27 |     auto add = [](auto a, auto b) {
     |          ^
../hello.cpp:31:10: remark: type of 'divide' deduced as '(lambda at ../hello.cpp:31:19)'
  31 |     auto divide = [](auto a, auto b) -> decltype(a / b) {
     |          ^
../hello.cpp:36:14: remark: return type of function 'getVal' deduced as 'int'
  36 |         auto getVal() const {
     |              ^
```

 
**Benefits to the Community**
- Improved Code Comprehension: Developers can easily see the types inferred by the compiler, which enhances their understanding of the code.
- Enhanced Debugging: During debugging, knowing the exact types can help diagnose type-related issues more efficiently.

>From df232a67ac0f5a294e8db4c86e10b6bdf664d673 Mon Sep 17 00:00:00 2001
From: Nisarga V <vnisarga at pe31.us.cray.com>
Date: Fri, 14 Jun 2024 01:16:38 -0500
Subject: [PATCH] [clang] Dump Auto Type Inference:  This pull request adds the
 -fdump-auto-type-inference option to Clang. When enabled, the compiler will
 emit messages describing the inferred types for auto declarations in C++11.
 This feature aids in understanding and debugging by providing clarity on the
 types deduced by the compiler.

---
 clang/include/clang/Driver/Options.td         |  4 ++
 clang/include/clang/Sema/Sema.h               | 12 +++++
 clang/lib/Sema/Sema.cpp                       | 25 +++++++++
 clang/lib/Sema/SemaDecl.cpp                   |  6 +++
 clang/lib/Sema/SemaStmt.cpp                   |  6 +++
 clang/test/Sema/fdump_auto-type-inference.cpp | 51 +++++++++++++++++++
 6 files changed, 104 insertions(+)
 create mode 100644 clang/test/Sema/fdump_auto-type-inference.cpp

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index f04c220d6e1db..655bfcd66e970 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<FrontendOpts<"ASTDumpFilter">>;
 def ast_dump_filter_EQ : Joined<["-"], "ast-dump-filter=">,
   Alias<ast_dump_filter>;
+def fdump_auto_type_inference : Flag<["-"], "fdump-auto-type-inference">, Group<f_Group>,
+    HelpText<"Dump auto type inference information">;
+def fno_dump_auto_type_inference : Flag<["-"], "fno-dump-auto-type-inference">,Group<f_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<FrontendOpts<"UseGlobalModuleIndex">>;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4d4579fcfd456..502ef30fe5a21 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 <deque>
 #include <memory>
 #include <optional>
@@ -77,6 +78,11 @@
 #include <tuple>
 #include <vector>
 
+namespace opts {
+// Option for dumping auto type inference
+extern llvm::cl::OptionCategory DumpAutoInference;
+extern llvm::cl::opt<bool> DumpAutoTypeInference;
+} // namespace opts
 namespace llvm {
 class APSInt;
 template <typename ValueT, typename ValueInfoT> 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 a612dcd4b4d03..13d137ec0e784 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<bool> 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<void()> Fn) {
   clang::runWithSufficientStackSpace([&] { warnStackExhausted(Loc); }, Fn);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4b9b735f1cfb4..ba5cf1868384e 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 57465d4a77ac2..e14f86f2450cd 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 0000000000000..0509933a0b4a8
--- /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 at -5 {{type of 'x' deduced as 'int'}}
+  // expected-remark at -4 {{type of 'y' deduced as 'double'}}
+  // expected-remark at -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 at +1{{type of 'x' deduced as 'int'}}
+    // expected-remark at +1{{type of 'y' deduced as 'double'}}
+    // expected-remark at +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 at +2{{type of 'add' deduced as '(lambda}}
+    // expected-remark at +1{{type of 'divide' deduced as '(lambda}}
+    // expected-remark at +1{{function return type of 'getVal' deduced as 'int'}}
+    
+    return 0;
+}



More information about the cfe-commits mailing list