summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/AST/ExprConstant.cpp46
-rw-r--r--clang/lib/Sema/SemaLambda.cpp2
-rw-r--r--clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp37
3 files changed, 78 insertions, 7 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 6dcb705c44d..bb0b8ba5c8b 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -4543,6 +4543,12 @@ public:
Call.getLValueBase().dyn_cast<const ValueDecl*>());
if (!FD)
return Error(Callee);
+ // Don't call function pointers which have been cast to some other type.
+ // Per DR (no number yet), the caller and callee can differ in noexcept.
+ if (!Info.Ctx.hasSameFunctionTypeIgnoringExceptionSpec(
+ CalleeType->getPointeeType(), FD->getType())) {
+ return Error(E);
+ }
// Overloaded operator calls to member functions are represented as normal
// calls with '*this' as the first argument.
@@ -4558,14 +4564,42 @@ public:
return false;
This = &ThisVal;
Args = Args.slice(1);
+ } else if (MD && MD->isLambdaStaticInvoker()) {
+ // Map the static invoker for the lambda back to the call operator.
+ // Conveniently, we don't have to slice out the 'this' argument (as is
+ // being done for the non-static case), since a static member function
+ // doesn't have an implicit argument passed in.
+ const CXXRecordDecl *ClosureClass = MD->getParent();
+ assert(
+ ClosureClass->captures_begin() == ClosureClass->captures_end() &&
+ "Number of captures must be zero for conversion to function-ptr");
+
+ const CXXMethodDecl *LambdaCallOp =
+ ClosureClass->getLambdaCallOperator();
+
+ // Set 'FD', the function that will be called below, to the call
+ // operator. If the closure object represents a generic lambda, find
+ // the corresponding specialization of the call operator.
+
+ if (ClosureClass->isGenericLambda()) {
+ assert(MD->isFunctionTemplateSpecialization() &&
+ "A generic lambda's static-invoker function must be a "
+ "template specialization");
+ const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs();
+ FunctionTemplateDecl *CallOpTemplate =
+ LambdaCallOp->getDescribedFunctionTemplate();
+ void *InsertPos = nullptr;
+ FunctionDecl *CorrespondingCallOpSpecialization =
+ CallOpTemplate->findSpecialization(TAL->asArray(), InsertPos);
+ assert(CorrespondingCallOpSpecialization &&
+ "We must always have a function call operator specialization "
+ "that corresponds to our static invoker specialization");
+ FD = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization);
+ } else
+ FD = LambdaCallOp;
}
- // Don't call function pointers which have been cast to some other type.
- // Per DR (no number yet), the caller and callee can differ in noexcept.
- if (!Info.Ctx.hasSameFunctionTypeIgnoringExceptionSpec(
- CalleeType->getPointeeType(), FD->getType())) {
- return Error(E);
- }
+
} else
return Error(E);
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 1680d8a6960..a0d574915eb 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1274,7 +1274,7 @@ static void addFunctionPointerConversion(Sema &S,
ConvTy,
ConvTSI,
/*isInline=*/true, /*isExplicit=*/false,
- /*isConstexpr=*/false,
+ /*isConstexpr=*/S.getLangOpts().CPlusPlus1z,
CallOperator->getBody()->getLocEnd());
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
diff --git a/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp b/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
index 90a07665cbf..f1f4cfe66c2 100644
--- a/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
+++ b/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
@@ -59,4 +59,41 @@ void f(char c) { //expected-note{{declared here}}
}
}
+
+namespace test_conversion_function_for_non_capturing_lambdas {
+
+namespace ns1 {
+auto L = [](int i) { return i; };
+constexpr int (*fpi)(int) = L;
+static_assert(fpi(3) == 3);
+auto GL = [](auto a) { return a; };
+
+constexpr char (*fp2)(char) = GL;
+constexpr double (*fp3)(double) = GL;
+constexpr const char* (*fp4)(const char*) = GL;
+static_assert(fp2('3') == '3');
+static_assert(fp3(3.14) == 3.14);
+constexpr const char *Str = "abc";
+static_assert(fp4(Str) == Str);
+
+auto NCL = [](int i) { static int j; return j; }; //expected-note{{declared here}}
+constexpr int (*fp5)(int) = NCL;
+constexpr int I = //expected-error{{must be initialized by a constant expression}}
+ fp5(5); //expected-note{{non-constexpr function}}
+
+namespace test_dont_always_instantiate_constexpr_templates {
+
+auto explicit_return_type = [](auto x) -> int { return x.get(); };
+decltype(explicit_return_type(0)) c; // OK
+
+auto deduced_return_type = [](auto x) { return x.get(); }; //expected-error{{not a structure or union}}
+decltype(deduced_return_type(0)) d; //expected-note{{requested here}}
+
+
+
+} // end ns test_dont_always_instantiate_constexpr_templates
+} // end ns1
+
+} // end ns test_conversion_function_for_non_capturing_lambdas
+
#endif // ndef CPP14_AND_EARLIER
OpenPOWER on IntegriCloud