Giter VIP home page Giter VIP logo

cppinsights's Introduction

cpp insights logo

C++ Insights - See your source code with the eyes of a compiler.

License download Build Status codecov Try online Documentation patreon

Open in Gitpod

Contents

What

C++ Insights is a Clang-based tool that does a source-to-source transformation. The goal of C++ Insights is to make things visible that normally and intentionally happen behind the scenes. It's about the magic the compiler does for us to make things work.

Take this piece of code for example:

class Base {
};

class Derived : public Base {
};

int main() {
  Derived d;

  Derived d2 = d;

  d2 = d;

  Base& b = d;
}

Nothing special, and of course, it compiles. This is the compiler's view on it:

class Base
{
  public:
  // inline constexpr Base() noexcept = default;
  // inline constexpr Base(const Base &) noexcept = default;
  // inline constexpr Base & operator=(const Base &) noexcept = default;
};



class Derived : public Base
{
  public:
  // inline constexpr Derived() noexcept = default;
  // inline constexpr Derived(const Derived &) noexcept = default;
  // inline constexpr Derived & operator=(const Derived &) noexcept = default;
};



int main()
{
  Derived d;
  Derived d2 = Derived(d);
  d2.operator=(d);
  Base & b = static_cast<Base&>(d);
  return 0;
}

You can see all the compiler-provided special member functions and the upcast from Derived to Base.

Why

C++ Insights is a Clang-based tool that does a source-to-source transformation. The goal of C++ Insights is to make things visible that normally and intentionally happen behind the scenes. It's about the magic the compiler does for us to make things work. Or looking through the classes of a compiler.

In 2017, I started looking into some new things we got with C++11, C++14, and C++17. Amazing things like lambdas, range-based for-loops, and structured bindings. I put it together in a talk. You can find the slides and a video online.

However, all that research and some of my training and teaching got me to start thinking about how it would be if we could see with the eyes of the compiler. Sure, there is an AST dump, at least for Clang. We can see what code the compiler generates from a C++ source snippet with tools like Compiler Explorer. However, what we see is assembler. Neither the AST nor the Compiler Explorer output is in the language I write code. Hence, I'm not very familiar with this output. Plus, when teaching students C++, showing an AST and explaining that it is all there was not quite satisfying for me.

I started to write a Clang-based tool that can transform a range-based for-loop into the compiler-internal version. Then, I did the same for structured bindings and lambdas. In the end, I did much more than initially planned. It shows where operators are invoked and places in which the compiler does some casting. C++ Insights can deduce the type behind auto or decltype. The goal is to produce compilable code. However, this is not possible in all places.

You can see, for example, the transformation of a lambda, range-based for-loop, or auto. Of course, you can transform any other C++ snippet.

See yourself. C++ Insights is available online: cppinsights.io.

Still, there is work to do.

I do not claim to get all the things right. I'm also working on supporting features from new standards, like C++20, at the moment. Please remember that C++ Insights is based on Clang and its understanding of the AST.

I did a couple of talks about C++ Insights since I released C++ Insights. For example, at C++ now. Here are the slides and the video.

Building

C++ Insights can be built inside the Clang source tree or outside.

Building on Windows

See Readme_Windows.md

Building on Arch Linux

To build with extra/clang use the following extra flags: -DINSIGHTS_USE_SYSTEM_INCLUDES=off -DCLANG_LINK_CLANG_DYLIB=on -DLLVM_LINK_LLVM_DYLIB=on

See #186 for an explanation of why INSIGHTS_USE_SYSTEM_INCLUDES needs to be turned off.

extra/clang and extra/llvm provide /usr/lib/{libclangAST.so,libLLVM*.a,libLLVM.so}. libclangAST.so needs libLLVM.so and there would be a conflict if libLLVM*.a (instead of libLLVM.so) are linked. See https://bugs.archlinux.org/task/60512

Building outside Clang

You need to have a Clang installation in the search path.

git clone https://github.com/andreasfertig/cppinsights.git
mkdir build && cd build
cmake -G"Ninja" ../cppinsights
ninja

The resulting binary (insights) can be found in the build folder.

Building inside Clang

The easiest way to build C++ Insights inside the Clang source tree is using the LLVM_EXTERNAL_PROJECTS option.

git clone https://github.com/llvm/llvm-project.git
git clone https://github.com/andreasfertig/cppinsights.git

mkdir build
cd build
cmake -G Ninja -D=CMAKE_BUILD_TYPE=Release -DLLVM_EXTERNAL_PROJECTS=cppinsights -DLLVM_EXTERNAL_CPPINSIGHTS_SOURCE_DIR=<PATH/TO/cppinsights>  [INSIGHTS CMAKE OPTIONS] ../llvm-project/llvm

ninja

cmake options

There are a couple of options that can be enabled with cmake:

Option Description Default
INSIGHTS_STRIP Strip insight after build ON
INSIGHTS_STATIC Use static linking OFF
INSIGHTS_COVERAGE Enable code coverage OFF
INSIGHTS_USE_LIBCPP Use libc++ for tests OFF
DEBUG Enable debug OFF

Building for ARM on macOS

It seems best to supply the architecture during configuration:

cmake -DCMAKE_OSX_ARCHITECTURES=arm64 ../cppinsights

Use it with Cevelop

git clone https://github.com/andreasfertig/cppinsights.git
mkdir build_eclipse
cd build_eclipse
cmake -G"Eclipse CDT4 - Unix Makefiles" ../cppinsights/

Then, in Cevelop Import -> General -> Existing Project into Workspace. Select build_eclipse. Enjoy editing with Cevelop.

Usage

Using C++ Insights is fairly simple:

insights <YOUR_CPP_FILE> -- -std=c++17

Things get complicated when it comes to the system-include paths. These paths are hard-coded in the binary, which seems to come from the compiler C++ Insights was built with. To help with that, check out scripts/getinclude.py. The script tries to collect the system-include paths from the compiler. Without an option, getinclude.py uses g++. You can also pass another compiler as a first argument.

Here is an example:

./scripts/getinclude.py
-isystem/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1 -isystem/usr/local/include -isystem/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/7.3.0/include -isystem/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -isystem/usr/include

The script can be used together with C++ Insights:

insights <YOUR_CPP_FILE> -- -std=c++17 `./scripts/getinclude.py`

Custom GCC installation

In case you have a custom build of the GCC compiler, for example, gcc-11.2.0, and NOT installed in the compiler in the default system path, then after building, Clang fails to find the correct libstdc++ path (GCC's STL). If you run into this situation, you can use "--gcc-toolchain=/path/GCC-1x.x.x/installed/path" to tell Clang/C++ Insights the location of the STL:

./cppinsights Insights.cpp -- --gcc-toolchain=${GCC_11_2_0_INSTALL_PATH} -std=c++20

Here "${GCC_11_2_0_INSTALL_PATH}" is the installation directory of your customized-built GCC. The option for Clang is described here.

Ready to use Docker container

There is also another GitHub project that sets up a docker container with the latest C++ Insights version in it: C++ Insights - Docker

C++ Insights @ Vim

A plugin for Vim is available at here.

C++ Insights @ VSCode

An extension for Visual Studio Code is available at the VS Code marketplace: C++ Insights - VSCode Extension.

C++ Insights @ brew

At least for macOS, you can install C++ Insights via Homebrew thanks to this formulae:

brew install cppinsights

Compatibility

I aim for the repository to compile with the latest version of Clang and at least the one before. The website tries to stay close to the latest release of Clang. However, due to certain issues (building Clang for Windows), the website's version is often delayed by a few months.

C++ Insights @ YouTube

I created a YouTube channel where I release a new video each month. In these videos, I use C++ Insights to show and explain certain C++ constructs, and sometimes I explain C++ Insights as well.

ToDo's

See TODO.

Get Involved

Support

If you like to support the project, consider submitting a patch. Another alternative is to become a GitHub Sponsor or a Patreon supporter.

cppinsights's People

Contributors

andreasfertig avatar ayazhafiz avatar devtbi avatar e-kwsm avatar freed-wu avatar galorojo avatar grishavanika avatar hftrader avatar kl7107 avatar lexasub avatar mergify[bot] avatar meysholdt avatar mys721tx avatar nikohoffren avatar nkid00 avatar pravic avatar rageking8 avatar viccie30 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cppinsights's Issues

Not able to execute below code.

Not able to run the code mentioned in PS on c++ insights.
Get the following error :

Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at [email protected] to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.

The smaller code snippets work.

Kindly mention if there is a limitation based on code length in c++ insights.

Thank you,
Kapil

PS : Code below compiles and executes well on Ubuntu 14.04 g++

`
#ifndef MY_STRING_H_
#define MY_STRING_H_

#include <cstring>
#include <iostream>
#include <memory>
#include <algorithm>
#include <stdexcept>
#include <limits>

namespace kapil {
class string final {
private:
size_t sz_;
std::unique_ptr<char[]> ptr_;
public:
string();
string(const string&);
string(string&&) noexcept;
explicit string(const char*);
explicit string(char);
~string() noexcept;

size_t size() const noexcept;
size_t length() const noexcept;
void resize(size_t, char ch = '\0');
void clear() noexcept;
bool empty() const noexcept;
char& at(size_t);
const char& at(size_t) const;
char& back();
const char& back() const;
char& front();
const char& front() const;
string& append(const string&);
string& append(const char*);
string& append(string&&);
string& append(char);
void push_back(char);
string& assign(const string&);
string& assign(const char*);
string& assign(string&&);
void swap(string&);
const char* c_str() const noexcept;
const char* data() const noexcept;

string& operator = (const string&);
string& operator = (string&&) noexcept;
string& operator = (const char*);
string& operator = (char);
string& operator += (const string&);
string& operator += (const char*);
string& operator += (char);
string& operator += (string&&);
char& operator[] (size_t);
const char& operator[] (size_t) const;

friend std::ostream& operator << (std::ostream&, const string&);
friend string operator + (const string&, const string&);
friend string operator + (const string&, const char*);
friend string operator + (const char*, const string&);
friend string operator + (string&&, string&&);
friend string operator + (string&&, const char*);
friend string operator + (const char*, string&&);
friend string operator + (const string&, string&&);
friend string operator + (string&&, const string&);
friend string operator + (const string&, char);
friend string operator + (char, const string&);
friend string operator + (string&&, char);
friend string operator + (char, string&&);
friend bool operator == (const string&, const string&) noexcept;
friend bool operator == (const string&, const char*) noexcept;
friend bool operator == (const char*, const string&) noexcept;
friend bool operator == (const string&, char) noexcept;
friend bool operator == (char, const string&) noexcept;
friend bool operator == (const string&, string&&) noexcept;
friend bool operator == (string&&, const string&) noexcept;
friend bool operator == (string&&, string&&) noexcept;
friend bool operator == (string&&, char) noexcept;
friend bool operator == (char, string&&) noexcept;
friend bool operator == (const char*, string&&) noexcept;
friend bool operator == (string&&, const char*) noexcept;
friend bool operator != (const string&, const string&) noexcept;
friend bool operator != (const string&, const char*) noexcept;
friend bool operator != (const char*, const string&) noexcept;
friend bool operator != (const string&, char) noexcept;
friend bool operator != (char, const string&) noexcept;
friend bool operator != (const string&, string&&) noexcept;
friend bool operator != (string&&, const string&) noexcept;
friend bool operator != (string&&, string&&) noexcept;
friend bool operator != (string&&, char) noexcept;
friend bool operator != (char, string&&) noexcept;
friend bool operator != (const char*, string&&) noexcept;
friend bool operator != (string&&, const char*) noexcept;

class iterator
{
private:
string* str_;
size_t index_;
public:
iterator(string* = nullptr, size_t = 0) noexcept;
iterator(const iterator&) noexcept;
iterator(iterator&&) noexcept;
~iterator() noexcept;

  iterator& operator = (const iterator&) noexcept;
  iterator& operator = (iterator&&) noexcept;
  bool operator != (const iterator&) const noexcept;
  bool operator == (const iterator&) const noexcept;
  iterator& operator ++ ();
  iterator& operator ++ (int);
  iterator& operator -- ();
  iterator& operator -- (int);
  char& operator * () const;

};

iterator begin();
iterator end();

class const_iterator
{
private:
const string* str_;
size_t index_;
public:
const_iterator(const string* = nullptr, size_t = 0);
const_iterator(const const_iterator&);
const_iterator(const_iterator&&) noexcept;
~const_iterator();

  const_iterator& operator = (const const_iterator&);
  const_iterator& operator = (const_iterator&&) noexcept;
  bool operator != (const const_iterator&) const noexcept;
  bool operator == (const const_iterator&) const noexcept;
  const_iterator& operator ++ ();
  const_iterator& operator ++ (int);
  const_iterator& operator -- ();
  const_iterator& operator -- (int);
  const char& operator * () const;

};

const_iterator cbegin();
const_iterator cend();

class reverse_iterator
{
private:
string* str_;
size_t index_;
public:
reverse_iterator(string* = nullptr, size_t = 0);
reverse_iterator(const reverse_iterator&);
reverse_iterator(reverse_iterator&&) noexcept;
~reverse_iterator();

  reverse_iterator& operator = (const reverse_iterator&);
  reverse_iterator& operator = (reverse_iterator&&) noexcept;
  bool operator != (const reverse_iterator&) const noexcept;
  bool operator == (const reverse_iterator&) const noexcept;
  reverse_iterator& operator ++ ();
  reverse_iterator& operator ++ (int);
  reverse_iterator& operator -- ();
  reverse_iterator& operator -- (int);
  char& operator * () const;

};

reverse_iterator rbegin();
reverse_iterator rend();

class reverse_const_iterator
{
private:
const string* str_;
size_t index_;
public:
reverse_const_iterator(const string* = nullptr, size_t = 0);
reverse_const_iterator(const reverse_const_iterator&);
reverse_const_iterator(reverse_const_iterator&&) noexcept;
~reverse_const_iterator();

  reverse_const_iterator& operator = (const reverse_const_iterator&);
  reverse_const_iterator& operator = (reverse_const_iterator&&) noexcept;
  bool operator != (const reverse_const_iterator&) const noexcept;
  bool operator == (const reverse_const_iterator&) const noexcept;
  reverse_const_iterator& operator ++ ();
  reverse_const_iterator& operator ++ (int);
  reverse_const_iterator& operator -- ();
  reverse_const_iterator& operator -- (int);
  const char& operator * () const;

};

reverse_const_iterator crbegin();
reverse_const_iterator crend();
};
} //kapil

namespace kapil {

/**************************************** member functions *********************/

string::string() {
ptr_ = std::make_unique<char[]>(1);
ptr_.get()[0] = '\0';
sz_ = 0;
}

string::string(const string& other) {
sz_ = other.sz_;
ptr_ = std::make_unique<char[]>(sz_ + 1);
std::strcpy(ptr_.get(), other.ptr_.get());
}

string::string(string&& rval) noexcept
: sz_{ rval.sz_ }, ptr_{ std::move(rval.ptr_) } {
}

string::string(const char* c_string) {
sz_ = std::strlen(c_string);
ptr_ = std::make_unique<char[]>(sz_ + 1);
std::strcpy(ptr_.get(), c_string);
}

string::string(char ch) {
sz_ = 1;
ptr_ = std::make_unique<char[]>(sz_ + 1);
ptr_.get()[0] = ch;
ptr_.get()[1] = '\0';
}

string::~string() noexcept {
ptr_.reset(nullptr);
sz_ = 0;
};

/**************************************** member functions *********************/

size_t string::size() const noexcept {
return sz_;
}

size_t string::length() const noexcept {
return sz_;
}

void string::resize(size_t n, char ch) {
if (n == sz_) {
return;
}

std::unique_ptr<char[]> temp = std::make_unique<char[]>(n + 1);

if (n < sz_) {
std::strncpy(temp.get(), ptr_.get(), n);
temp.get()[n] = '\0';
} else if (n > sz_) {
std::strncpy(temp.get(), ptr_.get(), sz_);
std::fill(temp.get() + sz_, temp.get() + n + 1, ch);
}

ptr_.reset(nullptr);
sz_ = n;
ptr_ = std::move(temp);
}

void string::clear() noexcept {
ptr_.reset(nullptr);
sz_ = 0;
}

bool string::empty() const noexcept {
return sz_ == 0;
}

char& string::at(size_t idx) {
if (idx < 0 || idx >= sz_) {
throw std::out_of_range{"out of range memory access"};
}
return (*this)[idx];
}

const char& string::at(size_t idx) const {
if (idx < 0 || idx >= sz_) {
throw std::out_of_range{"out of range memory access"};
}
return (*this)[idx];
}

char& string::back() {
return (*this)[sz_ - 1];
}

const char& string::back() const {
return (*this)[sz_ - 1];
}

char& string::front() {
return (*this)[0];
}

const char& string::front() const {
return (*this)[0];
}

string& string::append(const string& rhs) {
(*this) += rhs;
return *this;
}

string& string::append(const char* rhs) {
(*this) += rhs;
return *this;
}

string& string::append(string&& rhs) {
(*this) += rhs;
return *this;
}

string& string::append(char ch) {
(*this) += ch;
return *this;
}

void string::push_back(char ch) {
(*this) += ch;
return;
}

string& string::assign(const string& rhs) {
(*this) = rhs;
return *this;
}

string& string::assign(const char* rhs) {
(*this) = rhs;
return *this;
}

string& string::assign(string&& rhs) {
(*this) = rhs;
return *this;
}

void string::swap(string &str) {
string temp{str};
str = *this;
*this = temp;
}

const char* string::c_str() const noexcept {
return ptr_.get();
}

const char* string::data() const noexcept {
return c_str();
}

/**************************************** member operator overloads*********************/

string& string::operator = (const string& rhs) {
if (this != &rhs) {
ptr_.reset(nullptr);
sz_ = rhs.sz_;
ptr_ = std::make_unique<char[]>(sz_ + 1);
std::strcpy(ptr_.get(), rhs.ptr_.get());
}
return *this;
}

string& string::operator = (string&& rval) noexcept {
ptr_.reset(nullptr);
sz_ = rval.sz_;
ptr_ = std::move(rval.ptr_);
return *this;
}

string& string::operator = (const char* c_string) {
ptr_.reset(nullptr);
sz_ = std::strlen(c_string);
ptr_ = std::make_unique<char[]>(sz_ + 1);
std::strcpy(ptr_.get(), c_string);
return *this;
}

string& string::operator = (char ch) {
ptr_.reset(nullptr);
sz_ = 1;
ptr_ = std::make_unique<char[]>(sz_ + 1);
ptr_.get()[0] = ch;
ptr_.get()[1] = '\0';
return *this;
}

string& string::operator += (const string& rhs) {
std::unique_ptr<char[]> temp = std::make_unique<char[]>(sz_ + rhs.sz_ + 1);
std::strcpy(temp.get(), ptr_.get());
std::strcpy(temp.get() + sz_, rhs.ptr_.get());

ptr_.reset(nullptr);
sz_ += rhs.sz_;
ptr_ = std::move(temp);

return *this;
}

string& string::operator += (const char* rhs) {
size_t rhs_len = std::strlen(rhs);

std::unique_ptr<char[]> temp = std::make_unique<char[]>(sz_ + rhs_len + 1);
std::strcpy(temp.get(), ptr_.get());
std::strcpy(temp.get() + sz_, rhs);

ptr_.reset(nullptr);
sz_ += rhs_len;
ptr_ = std::move(temp);

return *this;
}

string& string::operator += (char ch) {
std::unique_ptr<char[]> temp = std::make_unique<char[]>(sz_ + 1 + 1);
std::strcpy(temp.get(), ptr_.get());
temp.get()[sz_] = ch;
temp.get()[sz_ + 1] = '\0';

ptr_.reset(nullptr);
sz_ += 1;
ptr_ = std::move(temp);

return *this;
}

string& string::operator += (string&& rval) {
std::unique_ptr<char[]> temp = std::make_unique<char[]>(sz_ + rval.sz_ + 1);
std::strcpy(temp.get(), rval.ptr_.get());
std::strcpy(temp.get() + sz_, rval.ptr_.get());

ptr_.reset(nullptr);
sz_ += rval.sz_;
ptr_ = std::move(temp);

return *this;
}

char& string::operator [] (size_t idx) {
return ptr_.get()[idx];
}

const char& string::operator [] (size_t idx) const {
return ptr_.get()[idx];
}

/**************************************** friend operator overloads *********************/

std::ostream& operator << (std::ostream& out, const string& str) {
if (str.size() > 0) {
out.write(str.c_str(), str.size());
}
return out;
}

string operator + (const string& lhs, const string& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (const string& lhs, const char* rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (const char* lhs, const string& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (string&& lhs, string&& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (string&& lhs, const char* rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (const char* lhs, string&& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (const string& lhs, string&& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (string&& lhs, const string& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (const string& lhs, char rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (char lhs, const string& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (string&& lhs, char rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (char lhs, string&& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

bool operator == (const string& lhs, const string& rhs) noexcept {
return (lhs.sz_ == rhs.sz_) &&
((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
}

bool operator == (const string& lhs, const char* rhs) noexcept {
return (lhs.sz_ == std::strlen(rhs)) &&
((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) == 0));
}

bool operator == (const char* lhs, const string& rhs) noexcept {
return (strlen(lhs) == rhs.sz_) &&
((rhs.sz_ == 0) ? true : (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) == 0));
}

bool operator == (const string& lhs, char rhs) noexcept {
return (lhs.sz_ == 1) &&
(lhs.ptr_.get()[0] == rhs);
}

bool operator == (char lhs, const string& rhs) noexcept {
return (rhs.sz_ == 1) &&
(lhs == rhs.ptr_.get()[0]);
}

bool operator == (const string& lhs, string&& rhs) noexcept {
return (lhs.sz_ == rhs.sz_) &&
((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
}

bool operator == (string&& lhs, const string& rhs) noexcept {
return (lhs.sz_ == rhs.sz_) &&
((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
}

bool operator == (string&& lhs, string&& rhs) noexcept {
return (lhs.sz_ == rhs.sz_) &&
((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
}

bool operator == (string&& lhs, char rhs) noexcept {
return (lhs.sz_ == 1) &&
(lhs.ptr_.get()[0] == rhs);
}

bool operator == (char lhs, string&& rhs) noexcept {
return (rhs.sz_ == 1) &&
(rhs.ptr_.get()[0] == lhs);
}

bool operator == (string&& lhs, const char* rhs) noexcept {
return (lhs.sz_ == std::strlen(rhs)) &&
((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) == 0));
}

bool operator == (const char* lhs, string && rhs) noexcept {
return (std::strlen(lhs) == rhs.sz_) &&
((rhs.sz_ == 0) ? true : (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) == 0));
}

bool operator != (const string& lhs, const string& rhs) noexcept {
return !(lhs == rhs);
}

bool operator != (const string& lhs, const char* rhs) noexcept {
return !(lhs == rhs);
}

bool operator != (const char* lhs, const string& rhs) noexcept {
return !(lhs == rhs);
}

bool operator != (const string& lhs, char rhs) noexcept {
return !(lhs == rhs);
}

bool operator != (char lhs, const string& rhs) noexcept {
return !(lhs == rhs);
}

bool operator != (const string& lhs, string&& rhs) noexcept {
return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
}

bool operator != (string&& lhs, const string& rhs) noexcept {
return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
}

bool operator != (string&& lhs, string&& rhs) noexcept {
return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
}

bool operator != (string&& lhs, char rhs) noexcept {
return (lhs.sz_ != 1) || (lhs.ptr_.get()[0] != rhs);
}

bool operator != (char lhs, string&& rhs) noexcept {
return (rhs.sz_ != 1) || (rhs.ptr_.get()[0] != lhs);
}

bool operator != (string&& lhs, const char* rhs) noexcept {
return (lhs.sz_ != std::strlen(rhs)) || (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) != 0);
}

bool operator != (const char* lhs, string && rhs) noexcept {
return (std::strlen(lhs) != rhs.sz_) || (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) != 0);
}

/**************************************** iterator related implementations *********************/

using iterator = string::iterator;

iterator::iterator(string *str, size_t index) noexcept
: str_{str}, index_{index} {
}

iterator::iterator(const iterator& itr) noexcept
: str_{itr.str_}, index_{itr.index_} {
}

iterator::iterator(iterator&& rval) noexcept
: str_{rval.str_}, index_{rval.index_} {
}

iterator::~iterator() noexcept {
str_ = nullptr;
index_ = 0;
}

iterator& iterator::operator = (const iterator& rhs) noexcept {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

iterator& iterator::operator = (iterator&& rhs) noexcept {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

bool iterator::operator != (const iterator& rhs) const noexcept {
return (str_ != rhs.str_) || (index_ != rhs.index_);
}

bool iterator::operator == (const iterator& rhs) const noexcept {
return (str_ == rhs.str_) && (index_ == rhs.index_);
}

iterator& iterator::operator ++ () {
++index_;
return *this;
}

iterator& iterator::operator ++ (int dummy) {
++(*this);
return *this;
}

iterator& iterator::operator -- () {
--index_;
return *this;
}

iterator& iterator::operator -- (int dummy) {
--(*this);
return *this;
}

char& iterator::operator * () const {
return (*str_)[index_];
}

iterator string::begin() {
return iterator(this);
}

iterator string::end() {
return iterator(this, sz_);
}

using const_iterator = string::const_iterator;

const_iterator::const_iterator(const string* str, size_t index)
: str_{str}, index_{index} {
}

const_iterator::const_iterator(const const_iterator& itr)
: str_{itr.str_}, index_{itr.index_} {
}

const_iterator::const_iterator(const_iterator&& rval) noexcept
: str_{rval.str_}, index_{rval.index_} {
}

const_iterator::~const_iterator() {
str_ = nullptr;
index_ = 0;
}

const_iterator& const_iterator::operator = (const const_iterator& rhs) {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

const_iterator& const_iterator::operator = (const_iterator&& rhs) noexcept {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

bool const_iterator::operator != (const const_iterator& rhs) const noexcept {
return (str_ != rhs.str_) || (index_ != rhs.index_);
}

bool const_iterator::operator == (const const_iterator& rhs) const noexcept {
return (str_ == rhs.str_) && (index_ == rhs.index_);
}

const_iterator& const_iterator::operator ++ () {
++index_;
return *this;
}

const_iterator& const_iterator::operator ++ (int dummy) {
++(*this);
return *this;
}

const_iterator& const_iterator::operator -- () {
--index_;
return *this;
}

const_iterator& const_iterator::operator -- (int dummy) {
--(*this);
return *this;
}

const char& const_iterator::operator * () const {
return (*str_)[index_];
}

const_iterator string::cbegin() {
return const_iterator(this);
}

const_iterator string::cend() {
return const_iterator(this, sz_);
}

using reverse_iterator = string::reverse_iterator;

reverse_iterator::reverse_iterator(string *str, size_t index)
: str_{str}, index_{index} {
}

reverse_iterator::reverse_iterator(const reverse_iterator& itr)
: str_{itr.str_}, index_{itr.index_} {
}

reverse_iterator::reverse_iterator(reverse_iterator&& rval) noexcept
: str_{rval.str_}, index_{rval.index_} {
}

reverse_iterator::~reverse_iterator() {
str_ = nullptr;
index_ = 0;
}

reverse_iterator& reverse_iterator::operator = (const reverse_iterator& rhs) {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

reverse_iterator& reverse_iterator::operator = (reverse_iterator&& rhs) noexcept {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

bool reverse_iterator::operator != (const reverse_iterator& rhs) const noexcept {
return (str_ != rhs.str_) || (index_ != rhs.index_);
}

bool reverse_iterator::operator == (const reverse_iterator& rhs) const noexcept {
return (str_ == rhs.str_) && (index_ == rhs.index_);
}

reverse_iterator& reverse_iterator::operator ++ () {
--index_;
return *this;
}

reverse_iterator& reverse_iterator::operator ++ (int dummy) {
++(*this);
return *this;
}

reverse_iterator& reverse_iterator::operator -- () {
++index_;
return *this;
}

reverse_iterator& reverse_iterator::operator -- (int dummy) {
--(*this);
return *this;
}

char& reverse_iterator::operator * () const {
return (*str_)[index_];
}

reverse_iterator string::rbegin() {
return reverse_iterator(this, sz_ - 1);
}

reverse_iterator string::rend() {
return reverse_iterator(this, -1);
}

using reverse_const_iterator = string::reverse_const_iterator;

reverse_const_iterator::reverse_const_iterator(const string* str, size_t index)
: str_{str}, index_{index} {
}

reverse_const_iterator::reverse_const_iterator(const reverse_const_iterator& itr)
: str_{itr.str_}, index_{itr.index_} {
}

reverse_const_iterator::reverse_const_iterator(reverse_const_iterator&& rval) noexcept
: str_{rval.str_}, index_{rval.index_} {
}

reverse_const_iterator::~reverse_const_iterator() {
str_ = nullptr;
index_ = 0;
}

reverse_const_iterator& reverse_const_iterator::operator = (const reverse_const_iterator& rhs) {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

reverse_const_iterator& reverse_const_iterator::operator = (reverse_const_iterator&& rhs) noexcept {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

bool reverse_const_iterator::operator != (const reverse_const_iterator& rhs) const noexcept {
return (str_ != rhs.str_) || (index_ != rhs.index_);
}

bool reverse_const_iterator::operator == (const reverse_const_iterator& rhs) const noexcept {
return (str_ == rhs.str_) && (index_ == rhs.index_);
}

reverse_const_iterator& reverse_const_iterator::operator ++ () {
--index_;
return *this;
}

reverse_const_iterator& reverse_const_iterator::operator ++ (int dummy) {
++(*this);
return *this;
}

reverse_const_iterator& reverse_const_iterator::operator -- () {
++index_;
return *this;
}

reverse_const_iterator& reverse_const_iterator::operator -- (int dummy) {
--(*this);
return *this;
}

const char& reverse_const_iterator::operator * () const {
return (*str_)[index_];
}

reverse_const_iterator string::crbegin() {
return reverse_const_iterator(this, sz_ - 1);
}

reverse_const_iterator string::crend() {
return reverse_const_iterator(this, -1);
}
} //kapil

#endif

using namespace kapil;

int main() {
string x1{"hey man"};
std::cout << x1;

std::cout << " start : \n";
//string s98 = string{"hello"} + string{" brother"};
std::cout << " start : \n";
string s1{"hello"};
string s2;
s2 = std::move(s1);
string s3 = string{"brother"};
string s4{s3};
string s5{""};
s5 = "batloluaaa";
s5 += s3;
s3 += " i am added to s3 as const char*";
s4 += string{" i am added as rval "};
s4 = s3 + s5 + " s3 + s5";
s3 = s5 + " i am s5 + const char*";
s2 = " i am const char* + s5" + s5;
s1 = s2 + 'a';
s1 = "kapil";
s1[0] = 's';
s1.back() = '$';
s1.at(3) = '';
s1.front() = '~';
s1.append('f');
s1.append("aswd");
s1.assign("char assigned");
s3.assign(s2);
std::cout << "\n should call move \n";
s4.assign(string{"moved"});
std::cout << "\n called move \n";
s4.swap(s1);
std::cout << "\n start of loop \n";
for (auto it : s1) {
std::cout << it;
}
std::cout << "\n end of loop \n";

if (s1 != s4) {
std::cout << " s1 != s2 \n";
}

s2 = s4 = {"same"};

if (s2 == s4) {
std::cout <<" s2 == s4 and same \n";
}

auto it53 = s2.cbegin();
auto it75 = s2.cbegin();
it75 = it53;

std::cout << "\n reverse loop start \n";
for (auto it = s2.rbegin(); it != s2.rend(); ++it) {
std::cout << *it;
}
std::cout << "\n reverse loop end \n";
std::cout << "\n const reverse loop start \n";
for (auto it = s2.crbegin(); it != s2.crend(); ++it) {
std::cout << *it;
}
std::cout << "\n const reverse loop end \n";

std::cout << " s1 : " << s1 << std::endl << " s2 : " << s2 << std::endl << " s3 : " << s3 << std::endl << " s4 : " << s4 << std::endl << " s5 : " << s5 << std::endl;

s1 = s2;

if (s1 == string{s2}) {
std::cout << " s1 is same as temp s2 \n";
}
return 0;
}
`

Lambda with copy capture with init fails

The following code was reported as broken:

#include <cstdio>
using namespace std;

int main()
{
  	static const char arr[] = { 1,2,3 };
	auto&& l=[ uuu = arr[1]]{
    	printf("a: %c\n", uuu);
    };
}

Support for C++17

It seems that the code uses CLang 4.9 on the website. Is it possible to update to Clang 6?
Also, it might be nice to choose which language standard to use.
I searched in vane for a place to add compiler flags.

Ellipsis missing from template instatiation

The instantiation from this code:

template<typename T>
void foo(T, ...) {}

int main(){
   foo(1, 2.);
}

Looks like this:

template<>
void foo<int>(int)
{
}

I think the signature should rather be void foo<int>(int, ...).

Try it on CppInsights.io

Structure binding a tuple-like type

#include <tuple>

std::tuple<int, float> foo();
 
auto [a, b] = foo();

transform into invalid syntax

#include <tuple>

std::tuple<int, float> foo();

 
std::tuple<int, float> __foo5 = foo();
std::tuple_element<0, std::tuple<int, float> >::type& a = std::get<0ul>(__foo5);
std::tuple_element<0, std::tuple<float> >::type& b = std::get<std::tuple_element<0, std::tuple<int, float> >::type && a = std::get<0ul>();
ulstd::tuple_element<0, std::tuple<float> >::type && b = std::get<1ul>();
(__foo5);

Template instantiation `()` handling issue

For some reason, the following code:
template<typename T> T foo() {return T(42); } int a = foo<int>();
produces:
return int42;
I would have expected return int(42)?
Using {} works fine, but () concatenate the type and the value somehow.

Lambda capture with renamed variables is wrongly instantiated

This code

#include <utility>

struct Movable
{
  Movable() {}
  Movable(Movable&& other) {}
  Movable& operator=(Movable&& other)
  {
      return *this;
  }
  
  Movable(const Movable&) = delete;
  Movable& operator=(const Movable&) = delete;
};

int main()
{
    Movable m;
    auto fun = [x = std::move(m)] () -> void {
    };
    fun();
}

instantiates the lambda with

__lambda_19 fun = __lambda_19{x};

However, this is wrong, because there is no x in main but only an m. Unfortunately, this example is even more comples, because m must be moved into the lambda, so also the constructor must be modified to move its arguments to the fields.

But a very cool project! 👍

Incorrect insight to const auto&

The following example

#include <iostream>
#include <memory>

std::shared_ptr<int> create() {
    return std::make_shared<int>(42);
}

int main()
{
  const auto& car = create(); // 'const' disappeared!
  //However, the following does not compile:
  //std::shared_ptr<int> & ar = create();
  //error: non-const lvalue reference to type 'shared_ptr<...>' cannot bind to a temporary of type 'shared_ptr<...>'
  
  //must be:
  const std::shared_ptr<int> & car2 = create();
}

is translated incorrectly:

#include <iostream>
#include <memory>

std::shared_ptr<int> create() {
    return std::make_shared<int>(42);
}

int main()
{
  std::shared_ptr<int> & car = create(); // 'const' disappeared!
  //However, the following does not compile:
  //std::shared_ptr<int> & ar = create();
  //error: non-const lvalue reference to type 'shared_ptr<...>' cannot bind to a temporary of type 'shared_ptr<...>'
  
  //must be:
  const std::shared_ptr<int> & car2 = create();
}

Similar happens with const auto&&.

Synchronize scrolling in the web version

Hello,

First of all, thanks for this interesting and very useful tool. It will be really helpful for newcomers and those who want to refresh his knowledge of modern C++ standards.

Just a suggestion of a tiny UX improvement: it'd be nice to synchronize code output in the web page when scrolling. Right now you have to scroll both panels manually to compare output side by side.

Optionally, may be something similar to diff view with slightly colored lines (of course, a full diff highlighting, like in github, isn't needed).

the generated URLs are to long in web version (for convenience)

Hello,

the domains which the tool generates are way too long. Is there the plan to change it like on compiler explorer does it?

comparison:

https://cppinsights.io/lnk?code=I2luY2x1ZGUgPHZlY3Rvcj4KI2luY2x1ZGUgPGNzdGRpbz4KCmludCBtYWluKCkKewogIHN0ZDo6dmVjdG9yPGludD4gdGVzdHsxLDIsMyw0LDV9OwogIAogIGZvcihhdXRvIGkgPSAwO2kgPCB0ZXN0LnNpemUoKTsrK2kpCiAgICArK3Rlc3RbaV07CiAKICAgICBjb25zdCBjaGFyIGFyclsxMF17Miw0LDYsOH07CgogICAgZm9yKGNvbnN0IGNoYXImIGMgOiBhcnIpCiAgICB7CiAgICAgIHByaW50ZigiYz0lY1xuIiwgYyk7CiAgICB9Cn0=&std=cpp17&rev=1.0

vs

https://gcc.godbolt.org/z/kv7yra

insights crashed on some invalid inputs

Crashed on the following piece of code:

#include <map>

int main()
// no open curly bracket here
    using Map = std::map<int, bool>;
    Map m;
    auto [it, ok] = m.insert({1, true});
}

Output is:

/home/insights/insights.cpp:5:5: error: expected function body after function declarator
    using Map = std::map<int, bool>;
    ^
/home/insights/insights.cpp:6:4: error: unknown type name 'Map'
        Map m;
        ^
/home/insights/insights.cpp:8:1: error: extraneous closing brace ('}')
}
^
[0x129475a]
....
[0x4a4407]
Segmentation fault (core dumped)

Without line

auto [it, ok] = m.insert({1, true});

there is no crash, just errors reported.

Error in Building Cppinsights

Hi @andreasfertig
I'm having trouble while installing cppinsights in my machine. I have summarised in this StackOverflow post about my problem. I don't know exactly what was the cause of this problem. I still think this was an issue with respect to my system, could you please help me to build cppinsights 👍

I will close this, once I get it properly installed.
Thanks

Lambda Capture by value for reference typed variables.

According to http://eel.is/c++draft/expr.prim.lambda#capture-10 and cppreference.org lambdas seems to capture references as copies of the decayed type.

But cppinsights does not agree given:

#include <string>

void func(const std::string& arg) {
 
  [arg] {
    return arg.size();
  };
}

int main() {
  std::string b;
  
  func(b);
}

It generates:

    const std::basic_string<char, std::char_traits<char>, std::allocator<char> > & arg;
    
    public: __lambda_5_3(const std::basic_string<char, std::char_traits<char>, std::allocator<char> > & _arg)
    : arg{_arg}
    {}

Where i would expect based on the linked section that it would produce:

    const std::basic_string<char, std::char_traits<char>, std::allocator<char> > arg;

unexpected behavior when explicitly instantiating a template

I'm not sure what the expected behavior is, but this snippet shows no template instantiation code being generated:

template<typename T>
struct Person
{
	int age, heightInInches;
	T distanceTraveled = T(); //default value
	float hairLength, GPA;
	unsigned int SATScore;

	T run(T speed, bool startWithLeftFoot);
};

template<typename T>
T Person<T>::run(T speed, bool left )
{
	return speed + (left ? 1 : 0);
}

template struct Person<int>;

int main()
{
	Person<int> f;
	auto x = f.run(2, true);
}

If you comment out the template struct Person<int>; it generates the expected template code.
Any ideas on why this happens?

I was expecting to this:

/* First instantiated from: insights.cpp:22 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct Person<int>
{
  int age;
  int heightInInches;
  int distanceTraveled = int();
  float hairLength;
  float GPA;
  unsigned int SATScore;
  int run(int speed, bool left)
  {
    return speed + (left ? 1 : 0);
  }
  
  // inline Person() noexcept = default;
  // inline constexpr Person(const Person<int> &) = default;
  // inline constexpr Person(Person<int> &&) = default;
};

Incorrect output when special member function is default

Output is incorrect when special member function is marked default outside of a class definition:

struct Base
{
    Base();
    Base(const Base &);
    ~Base();
};

Base::Base() = default;
Base::Base(const Base &) = default;
Base::~Base() = default;

Output is:

struct Base
{
	Base();
 
 ;
    Base(const Base &);
    
    ;
    ~Base() noexcept;
    ;
};

Base::Base() = default;

{
}

 = default;
Base::Base(const Base &) = default;

{
}

 = default;
Base::~Base() noexcept
{
}
 = default;

Missing includes stddef.h

Having trouble running CPP Insights on 18.04 with gcc 7.3

I run insights main.cpp -- -std=c++14 $(python2 /tmp/cppinsights/scripts/getinclude.py) from inside my source directory, that evaluates to:

insights main.cpp -- -std=c++14 -isystem/usr/lib/gcc/x86_64-linux-gnu/7/cc1plus -E              \                                                                                                                                                                               
   -quiet -v -imultiarch x86_64-linux-gnu -D_GNU_SOURCE /dev/null -mtune=generic                \                                                                                                                                                                               
   -march=x86-64 -fstack-protector-strong -Wformat -Wformat-security -isystem/usr/include/c++/7 \                                                                                                                                                                               
   -isystem/usr/include/x86_64-linux-gnu/c++/7 -isystem/usr/include/c++/7/backward              \
   -isystem/usr/lib/gcc/x86_64-linux-gnu/7/include -isystem/usr/local/include                   \
   -isystem/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed -isystem/usr/include/x86_64-linux-gnu  \
   -isystem/usr/include   

Which fails with:

$ /tmp/build/insights main.cpp -- -std=c++14 $(python2 /tmp/cppinsights/scripts/getinclude.py)
clang version 7.0.1 (tags/RELEASE_701/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir:
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7.3.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7.3.0
Candidate multilib: .;@m64
Selected multilib: .;@m64
In file included from /home/matt/workspace/matt-utils/map_point/main.cpp:1:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/iostream:39:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/ostream:38:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/ios:38:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/iosfwd:40:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/postypes.h:40:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/cwchar:44:
/usr/include/wchar.h:35:10: fatal error: 'stddef.h' file not found
#include <stddef.h>
         ^~~~~~~~~~
#include <iostream>
 
// ......

1 error generated.
Error while processing /home/matt/workspace/matt-utils/map_point/main.cpp.

I received similar errors on a 16.04 box where I was using gcc 7 via update-alternatives, which is why I moved to an 18.04 box, but still have the same problems.

I definitely have stddef.h, even in the search paths being provided:

/usr/include/linux/stddef.h                                                                                                                                                                                                                                                     
/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h 

My current directory contains a compile_commands.json.

Am I missing something?

`static` local variables : show the initialization checks

When static is used in a function, initialization of the variable will only happen on the first time the block scoped is reached. Since c++11, this is even thread_safe.

I suggest transforming the following code:

struct StructWithCtor
{
    StructWithCtor() { }
};

void func()
{
    static StructWithCtor structWithCtorInstance;
}

to the following for C++11 onward

struct StructWithCtor
{
    StructWithCtor() { }
};

void func()
{
//  static local variable means we need to support thread-safe, one-time initialization . The compiler will generate code like the following:
//
//  if ( obj_guard.first_byte == 0 ) {
//      if ( __cxa_guard_acquire(&obj_guard) ) {
//        try {
//          ... initialize the object structWithCtorInstance ...;
//        } 
//        catch (...) {
//          __cxa_guard_abort(&obj_guard);
//          throw;
//        }
//        ... queue object destructor of structWithCtorInstance with __cxa_atexit() ...;
//        __cxa_guard_release(&obj_guard);
//      }
//   }
//
    static StructWithCtor structWithCtorInstance;
}

Note the comment is adapted from Apple Clang : www.opensource.apple.com/source/libcppabi/libcppabi-14/src/cxa_guard.cxx

I think in this case we can leave it as a comment, because we would otherwise need to add something like
alignas(alignof(StructWithCtor)) char func_structWithCtorInstance _storage[sizeof(StructWithCtor)]; in the global scope and pull in the <new> header for placement new and then have new (&func_structWithCtor_storage) StructWithCtor();.

Casting in class error

There is a small bug when casting is done with a class member. As an example:

class Simple 
{
    int p;
  public:
    double get() {return p;}
};

yields

class Simple 
{
    int p;
  public:
    double get() {return static_cast<double>(this->p)p;}
};

An additionnal p is added after the cast, making the resulting code uncompilable.

Other than that, it is a great project !

usingShadow unsued variable

I receive this error when building off master ( e8965f7 )

FAILED: CMakeFiles/insights.dir/FunctionDeclHandler.cpp.o
ccache /usr/bin/c++   -I/usr/local/clang+llvm-7.0.1-x86_64-linux-gnu-ubuntu-18.04/include -I/tmp/cppinsights/. -Igenerated -isystem/usr/local/clang+llvm-7.0.1-x86_64-linux-gnu-ubuntu-18.04/include  -fPIC -fvisibility-inlines-hidden -Werror=date-time  -std=c++11 -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long  -Wnon-virtual-dtor -Wdelete-non-virtual-dtor  -ffunction-sections -fdata-sections -O3 -DNDEBUG  -fno-exceptions -fno-rtti -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -std=c++1z -Wextra -Wold-style-cast -Werror -Wsuggest-override -Wuseless-cast -Wno-overloaded-virtual -MD -MT CMakeFiles/insights.dir/FunctionDeclHandler.cpp.o -MF CMakeFiles/insights.dir/FunctionDeclHandler.cpp.o.d -o CMakeFiles/insights.dir/FunctionDeclHandler.cpp.o -c /tmp/cppinsights/FunctionDeclHandler.cpp
/tmp/cppinsights/FunctionDeclHandler.cpp: In member function ‘virtual void clang::insights::FunctionDeclHandler::run(const clang::ast_matchers::MatchFinder::MatchResult&)’:                                                                                                   
/tmp/cppinsights/FunctionDeclHandler.cpp:105:28: error: unused variable ‘usingShadow’ [-Werror=unused-variable]
             if(const auto* usingShadow = dyn_cast_or_null<ConstructorUsingShadowDecl>(shadow)) {
                            ^~~~~~~~~~~
cc1plus: all warnings being treated as errors

To get around it I delete the variable declaration.

g++ --version
g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

I get this on 16.04 and 18.04

Generated function specializations: Parameters generated from parameter packs use the same name

C++ Insights generates explicit specializations for template functions. When the primary function template contains any parameter packs, the parameters generated from the pack in the specialization will all use the same name. It would be nice for the names to be distinguished.

See below:

Input C++ Insights Desired
template<typename... T>
int func(T... t) {
    return func(t...);
}
int _ = func(5, 5);

#ifdef USE_TEMPLATE
template<>
int func<int, int>(int t, int t)
{
  return func(t, t);
}
#endif
int _ = func(5, 5);

#ifdef USE_TEMPLATE
template<>
int func<int, int>(int t1, int t2)
{
  return func(t1, t2);
}
#endif
int _ = func(5, 5);

Fixing this requires C++ Insights to detect which ParmVarDecls in a specialized FunctionDecl correspond to parameter packs in the primary function template (and then just suffix them with a counter, for instance). Annoyingly, I haven't found a good way in libclang to do so other than traversing all primary function template parameters and comparing them by name to the current ParmVarDecl :/

Folding expressions missing parenthesis

Argument is missed in case chrono_literals

#include <chrono>
#include <string>

int main()
{
    using namespace std::literals;
    std::chrono::seconds t = 10s;
}
#include <chrono>
#include <string>

int main()
{
    using namespace std::literals;
    std::chrono::seconds t = std::operator""s();
}

Expansion of global lambda expressions is broken

Lambda expressions at global scope generate unintelligible output. C++ Insights is supposed to replace them with equivalent, explicit class definitions, but this only seems to work properly for lambda expressions defined inside a function.

The following table illustrates the output for a locally defined lambda (fine) vs. two instances of global lambdas (broken).

Input C++ Insights
int main() {
    auto x = [a=5](int b) {
        return b*a;
    };
}
int main() {
  class __lambda_10_14 {
    public: inline /*constexpr */ int operator()(int b) const {
      return b * a;
    }
    private:
    int a;
    public:
    __lambda_10_14(int _a)
        : a{_a}
        {}
  };
 __lambda_10_14 x = __lambda_10_14{5};
}

auto x = []() {
    return 5;
};
__lambda_1_10 x = /* public: inline ~() noexcept; */
static inline int __invoke();
         ;
auto x2 = [a=5](int b) {
    return b*a;
};
__lambda_5_11 x2 = /* public: inline ~() noexcept; */
[inta=5](int binline constexpr int operator()(int b) const
{
return b * a;
}
;

Providing more demo code to show in C++ Insights

One request I got multiple times is to have more example transformations available. In a drop-down list or something. I opened this issue and asking for submissions. Which code-snippets should be on such a list?

Reference collapsing works wrong

For the following piece of code:

template <class T>
void foo(T && t)
{ }

struct Test {};

int main()
{
    Test test;
    foo(test);
    return 0;
}

output of an instantiation of foo is the following:

/* First instantiated from: insights.cpp:10 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void foo<Test &>(Test && t)
{
}
#endif

Argument type should be Test & but not Test && because of reference collapsing.

Brokenness for custom string literals

I just had the following code:

#include <string>
#include <vector>

int main()
{
  using namespace std::string_literals;
 
  std::vector<std::string> foo{"foo"s, "bar"s};
}

...and cppinsights gave me the following output:

#include <string>
#include <vector>

int main()
{
  using namespace std::string_literals;
 
  std::vector<std::string> foo{ std::initializer_list<std::basic_string<char> >{ std::operator""s("foo", 3ul), std::operator""s(std::operator""s("foo", 3ul) 3std::operator""s("bar", 3ul)};
}

Note especially the 3std.

missed template instantiation

Cppinsights.io doesn't show the template instantiation for max in the following code:

#include <string>
#include <utility>

template <typename T, typename Comp>
T& max(T& v1, T& v2, Comp&& comp) {
    return std::forward<Comp>(comp)(v1, v2)
           ? v2
           : v1;
}

void foo() {
    constexpr auto longer = [](auto&& s1, auto&& s2){
        return s1.length() < s2.length();
    };

    const auto s1 = std::string{"foo"};
    const auto s2 = std::string("barr");

    auto l5 = max(s1, s2, longer);
}

Note: it would be nice if the website showed version info or commit hash that I could include into the bug report.

LLVMSymbolizer: error reading file: No such file or directory

I have installed cppinsights in my PC. When I run cppinsights it throws some error like this,

LLVMSymbolizer: error reading file: No such file or directory
#0 0x000000000156219a (insights+0x156219a)
#1 0x00000000015605c4 (insights+0x15605c4)
#2 0x0000000001560702 (insights+0x1560702)
#3 0x00007f0326e3f890 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x12890)
#4 0x000000000054bb7a (insights+0x54bb7a)
#5 0x000000000051b0ca (insights+0x51b0ca)
#6 0x00000000005dccb0 (insights+0x5dccb0)
#7 0x00000000005e1715 (insights+0x5e1715)
#8 0x00000000005a19ae (insights+0x5a19ae)
#9 0x000000000053f484 (insights+0x53f484)
#10 0x000000000053607c (insights+0x53607c)
#11 0x000000000053b1ee (insights+0x53b1ee)
#12 0x000000000053ddb2 (insights+0x53ddb2)
#13 0x000000000051a869 (insights+0x51a869)
#14 0x00007f0326119b97 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b97)
#15 0x00000000004f53fa (insights+0x4f53fa)
Segmentation fault (core dumped)

What does this error information represent ? How can I get-rid of this ?

Thanks

Incorrect return type of a function returning a pointer to an array

See #74.

For this snippet

auto f(int i)
{ // also `decltype(auto) f(int i)`, `int(*f(int i))[3]` and `auto f(int i) -> int(*)[3]`
  static int arr[5][3];
  return &arr[i];
}

Insights incorrectly outputs

int (*)[3] f(int i)
{
  static int arr[5][3];
  return &arr[i];
}

and for this snippet

auto *f(int i)
{
  static int arr[5][3];
  return &arr[i];
}

Insights incorrectly outputs

int *[3] f(int i)
{
  static int arr[5][3];
  return &arr[i];
}

instead of the correct output for both snippets.

int(*f(int i))[3]
{
  static int arr[5][3];
  return &arr[i];
}

Insight is screwed for top-level variables with type placeholder and an array new expression initializers

auto p = new int[2];

becomes

int * p = new int[22;

The same happens for the decltype(auto) placeholder.
For multidimensional arrays, each index gets screwed, e.g. [2][3] becomes [22[33.
For index ranges > 9, e.g. [123][456], only the first digit is doubled: [1123[4456.
Hexadecimal integer literals screw it even more. new int[0x02] becomes new in2.
Octal integer literals in multidimensional array new expressions also result in a very funny output. new int[02][03] becomes new int 2][3.

Also note the additional newline added after every such declaration.

There is no problem with non-array new expressions and with array new expression when variable type is not deduced.

Nonexistent variable used, with unbalanced parentheses

This example on cppinsights.io:

#include <map>

int main()
{
    std::map<int, int> map{{1, 2}};
    auto [key, value] = *map.begin();
}

apparently desugars to

#include <map>

int main()
{
    std::map<int, int> map{ std::initializer_list<std::pair<const int, int> >{ std::pair<const int, int>(1, 2) } };
    std::pair<const int, int> __operator6 = std::pair<const int, int>(map.begin().operator*());
    std::tuple_element<0, std::pair<const int, int> >::type&& key = std::get<0ul>(__operator6);
    std::tuple_element<1, std::pair<const int, int> >::type&& value = std::get<1ul>(__opemap.begin().operator*() 
}

But __opemap.begin().operator*() should presumably be __operator6)

class/fun templates + decltype/decltype(auto) + one screen program = CRASH

This example causes https://cppinsights.io/ 's crash with different ways depending on how many lines in main() are commented. It is impossible to uncomment even a single line in main() without causing a crash.
The code compiles and works at least here.
The origin of the code is mentioned here, the first link in the article (which is translated by Google). I just removed "using namespace std;" from the original code, and corrected the affected part of the code by adding "std::" prefix where necessary.

Improve auto&&

The example for range-based for-loops on the about page transforms this piece of code:

#include <cstdio>

int main()
{
    const char arr[]{2,4,6,8,10};

    for(const char& c : arr)
    {
      printf("c=%c\n", c);
    }
}

into this:

#include <cstdio>

int main()
{
    const char arr[]{2,4,6,8,10};

    {
       auto&& __range1 = arr;
       const char * __begin1 = __range1;
       const char * __end1 = __range1 + 5l;
       
       for( ; __begin1 != __end1; ++__begin1 )
       {
         const char & c = *__begin1;
         printf("c=%c\n", static_cast<int>(c));
       }
     }
}

Leaving the auto&& __range1 = arr; is wrong as it was pointed out here.

Nested lambdas yield broken tokens

Found this on LLVM Weekly. Neat project.

Unfortunately, lambda handling seems quite buggy. For example:

void x()
{
  auto a = [](){
    [](){};
  };
}
void x()
{

   class __lambda_3
   {
     public: inline /*constexpr */ void operator()() const
     {
       __lambda_4;
     }
     
   };
   
   
   class __lambda_4
   {
     public: inline /*constexpr */ void operator()() const
     {
     }
     
   };
   
     __lambda_3 a = __lambda_4{}da_3{};
}

I'm not sure what __lambda_3; in operator() is supposed to do, and __lambda_4{}da_3{} is nonsense.

I suspect you're replacing the substring at [4,7) with something longer, then doing another replacement on the same line, without adjusting the offsets to account for the previous replacement. This yields lots of strange output (another example: removing auto a = makes it emit lambdas in the output), but I think most or all of it is all the same root cause.

(Additionally, two lambdas on the same line expand to two classes with the same name. Append column number to subsequent ones, maybe?)

limits.h header isn't in include path

If you include the standard C header limits.h, you get a fatal error: 'limits.h' file not found. The header climits is found, but since climits includes limits.h, compilation fails with the same error.

Missed const qualifier in structured binding

#include <string>
#include <unordered_map>

using namespace std;

int main()
{
    unordered_map<string, string> m;
    for (auto & [key, value] : m) {
      
    }
}
#include <string>
#include <unordered_map>

using namespace std;

int main()
{
  unordered_map<std::string, std::string> m = std::unordered_map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::hash<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >();
  {
    std::unordered_map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::hash<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > & __range1 = m;
    std::__detail::_Node_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, 0, 1> __begin1 = __range1.begin();
    std::__detail::_Node_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, 0, 1> __end1 = __range1.end();
    
    for( ; std::__detail::operator!=(__begin1, __end1); __begin1.operator++() )
    {
      std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > & __operator9 = __begin1.operator*();
      std::basic_string<char, std::char_traits<char>, std::allocator<char> >& key = std::get<0ul>(__operator9); // missed const qualifier for key 
      std::basic_string<char, std::char_traits<char>, std::allocator<char> >& value = std::get<1ul>(__operator9);
    }
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.