Skip to content

Commit

Permalink
Merge pull request #210 from andreasfertig/fixIssue205
Browse files Browse the repository at this point in the history
Fixed #205: Make lambdas as in class initializer work.
  • Loading branch information
andreasfertig authored Jul 16, 2019
2 parents 8a47db1 + b852329 commit e7675ae
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 6 deletions.
26 changes: 20 additions & 6 deletions CodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ OutputFormatHelper& CodeGenerator::LambdaScopeHandler::GetBuffer(OutputFormatHel
case LambdaCallerType::ReturnStmt:
case LambdaCallerType::OperatorCallExpr:
case LambdaCallerType::MemberCallExpr:
case LambdaCallerType::BinaryOperator: return &l;
case LambdaCallerType::BinaryOperator:
case LambdaCallerType::CXXMethodDecl: return &l;
default: break;
}
}
Expand Down Expand Up @@ -1783,16 +1784,15 @@ void CodeGenerator::InsertArg(const TypedefDecl* stmt)
}
//-----------------------------------------------------------------------------

void CodeGenerator::InsertCXXMethodDecl(const CXXMethodDecl* stmt, SkipBody skipBody)
void CodeGenerator::InsertCXXMethodHeader(const CXXMethodDecl* stmt, OutputFormatHelper& initOutputFormatHelper)
{
OutputFormatHelper initOutputFormatHelper{};
initOutputFormatHelper.SetIndent(mOutputFormatHelper, OutputFormatHelper::SkipIndenting::Yes);
LAMBDA_SCOPE_HELPER(CXXMethodDecl);
CXXConstructorDecl* cxxInheritedCtorDecl{nullptr};

// travers the ctor inline init statements first to find a potential CXXInheritedCtorInitExpr. This carries the
// Traverse the ctor inline init statements first to find a potential CXXInheritedCtorInitExpr. This carries the
// name and the type. The CXXMethodDecl above knows only the type.
if(const auto* ctor = dyn_cast_or_null<CXXConstructorDecl>(stmt)) {
CodeGenerator codeGenerator{initOutputFormatHelper};
CodeGenerator codeGenerator{initOutputFormatHelper, mLambdaStack};
OnceTrue first{};

for(const auto* init : ctor->inits()) {
Expand Down Expand Up @@ -1827,6 +1827,15 @@ void CodeGenerator::InsertCXXMethodDecl(const CXXMethodDecl* stmt, SkipBody skip
} else if(stmt->isDeleted()) {
mOutputFormatHelper.AppendNewLine(" = delete;");
}
}
//-----------------------------------------------------------------------------

void CodeGenerator::InsertCXXMethodDecl(const CXXMethodDecl* stmt, SkipBody skipBody)
{
OutputFormatHelper initOutputFormatHelper{};
initOutputFormatHelper.SetIndent(mOutputFormatHelper, OutputFormatHelper::SkipIndenting::Yes);

InsertCXXMethodHeader(stmt, initOutputFormatHelper);

if(not stmt->isUserProvided()) {
InsertTemplateGuardEnd(stmt);
Expand Down Expand Up @@ -2227,6 +2236,11 @@ void CodeGenerator::InsertArg(const TypeAliasTemplateDecl* stmt)

void CodeGenerator::InsertArg(const CXXRecordDecl* stmt)
{
// Prevent a case like in #205 where the lambda appears twice.
if(stmt->isLambda() && (mLambdaStack.empty() || (nullptr == mLambdaExpr))) {
return;
}

// we require the if-guard only if it is a compiler generated specialization. If it is a hand-written variant it
// should compile.
const bool isClassTemplateSpecialization{[&] {
Expand Down
5 changes: 5 additions & 0 deletions CodeGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class CodeGenerator
LambdaExpr,
ReturnStmt,
BinaryOperator,
CXXMethodDecl,
};

class LambdaHelper : public StackListEntry<LambdaHelper>
Expand Down Expand Up @@ -183,6 +184,10 @@ class CodeGenerator
bool InsertLambdaStaticInvoker(const CXXMethodDecl* cxxMethodDecl);
void InsertTemplateParameters(const TemplateParameterList& list);

/// For a special case, when a LambdaExpr occurs in a Constructor from an
/// in class initializer, there is a need for a more narrow scope for the \c LAMBDA_SCOPE_HELPER.
void InsertCXXMethodHeader(const CXXMethodDecl* stmt, OutputFormatHelper& initOutputFormatHelper);

void InsertTemplateGuardBegin(const FunctionDecl* stmt);
void InsertTemplateGuardEnd(const FunctionDecl* stmt);

Expand Down
15 changes: 15 additions & 0 deletions tests/Issue205.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include <functional>
#include <iostream>
class EventContainer {
private:
int val = 1234;
std::function<void()> something = [=]() {
std::cout << this->val;
};
};

int main() {
// get the default constructor generated.
EventContainer e;
return 0;
}
46 changes: 46 additions & 0 deletions tests/Issue205.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include <functional>
#include <iostream>
class EventContainer
{

private:
int val;
std::function<void ()> something;
public:
// inline EventContainer(const EventContainer &) = default;
// inline EventContainer(EventContainer &&) = default;
// inline EventContainer & operator=(EventContainer &&) = default;
// inline ~EventContainer() noexcept = default;

public:

class __lambda_6_43
{
EventContainer * __this;
public:
inline /*constexpr */ void operator()() const
{
std::cout.operator<<(__this->val);
}

// inline /*constexpr */ __lambda_6_43 & operator=(const __lambda_6_43 &) = default;
// inline /*constexpr */ __lambda_6_43(const __lambda_6_43 &) noexcept = default;
// inline /*constexpr */ __lambda_6_43(__lambda_6_43 &&) noexcept = default;
public: __lambda_6_43(EventContainer * _this)
: __this{_this}

{}

} __lambda_6_43{this};

// inline constexpr EventContainer() noexcept(false) = default;
};



int main()
{
EventContainer e = EventContainer();
return 0;
}

17 changes: 17 additions & 0 deletions tests/Issue205_2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <functional>
#include <iostream>
class EventContainer {
private:
int val = 1234;
std::function<void()> something = [=]() {
std::cout << this->val;
};

public:
EventContainer() : val{1235}{}
};

int main() {
// get the default constructor generated.
EventContainer e;
}
50 changes: 50 additions & 0 deletions tests/Issue205_2.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include <functional>
#include <iostream>
class EventContainer
{

private:
int val;
std::function<void ()> something;

public:

class __lambda_6_43
{
EventContainer * __this;
public:
inline /*constexpr */ void operator()() const
{
std::cout.operator<<(__this->val);
}

// inline /*constexpr */ __lambda_6_43 & operator=(const __lambda_6_43 &) = default;
// inline /*constexpr */ __lambda_6_43(const __lambda_6_43 &) noexcept = default;
// inline /*constexpr */ __lambda_6_43(__lambda_6_43 &&) noexcept = default;
public: __lambda_6_43(EventContainer * _this)
: __this{_this}

{}

} __lambda_6_43{this};

inline EventContainer()
: val{1235}
, something{std::function<void ()>(__lambda_6_43)}
{
}

// inline EventContainer(const EventContainer &) = default;
// inline EventContainer(EventContainer &&) = default;
// inline EventContainer & operator=(EventContainer &&) = default;
// inline ~EventContainer() noexcept = default;

};



int main()
{
EventContainer e = EventContainer();
}

25 changes: 25 additions & 0 deletions tests/LambdaAndInClassInitializerTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// std::function mock up
template<typename ReturnValue, typename... Args>
class function
{
public:
function() = default;

template<typename T>
function(T&& f)
{}
};

// part of #205
class EventContainer {
private:
int val = 1234;
function<void()> something = [=]() {
this->val;
};
};

int main() {
// get the default constructor generated.
EventContainer e;
}
93 changes: 93 additions & 0 deletions tests/LambdaAndInClassInitializerTest.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// std::function mock up
template<typename ReturnValue, typename... Args>
class function
{
public:
function() = default;

template<typename T>
function(T&& f)
{}
};

/* First instantiated from: LambdaAndInClassInitializerTest.cpp:17 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
class function<void ()>
{

public:
inline constexpr function() = default;
template<typename T>
inline function(T && f);


/* First instantiated from: LambdaAndInClassInitializerTest.cpp:17 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
inline function<__lambda_17_38>(__lambda_17_38 && f)
{
}
#endif



#ifdef INSIGHTS_USE_TEMPLATE
template<>
inline function<const function<void ()> &>(function<void ()> & f);
#endif



#ifdef INSIGHTS_USE_TEMPLATE
template<>
inline function<function<void ()> >(function<void ()> && f);
#endif


// inline constexpr function(const function<void ()> &) = default;
// inline constexpr function(function<void ()> &&) = default;
// inline ~function() noexcept = default;
};

#endif


// part of #205
class EventContainer
{

private:
int val;
function<void ()> something;

public:

class __lambda_17_38
{
EventContainer * __this;
public:
inline /*constexpr */ void operator()() const
{
__this->val;
}

public: __lambda_17_38(EventContainer * _this)
: __this{_this}

{}

} __lambda_17_38{this};

// inline constexpr EventContainer() noexcept(false) = default;
// inline constexpr EventContainer(const EventContainer &) = default;
// inline constexpr EventContainer(EventContainer &&) = default;
};



int main()
{
EventContainer e = EventContainer();
}

0 comments on commit e7675ae

Please sign in to comment.