Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -578,6 +578,8 @@ PartialDiagnostic::StorageAllocator &getDiagAllocator() { return DiagAllocator; } + bool isEmptyOrContainsOnlyWarningOrIgnorableDiagnostics( + ArrayRef PartialDiags) const; const TargetInfo &getTargetInfo() const { return *Target; } const TargetInfo *getAuxTargetInfo() const { return AuxTarget; } Index: include/clang/Basic/DiagnosticASTKinds.td =================================================================== --- include/clang/Basic/DiagnosticASTKinds.td +++ include/clang/Basic/DiagnosticASTKinds.td @@ -158,6 +158,15 @@ // in Sema. def note_unimplemented_constexpr_lambda_feature_ast : Note< "unimplemented constexpr lambda feature: %0 (coming soon!)">; + + // C++1z constexpr lambda expressions + def warn_cxx14_compat_constexpr_conversion_on_lambda : Warning< + "constexpr conversion to pointer-to-function on lambdas is " + "incompatible with C++ standards before C++1z">, + InGroup, DefaultIgnore; + def ext_constexpr_conversion_on_lambda_cxx1z : ExtWarn< + "constexpr conversion to pointer-to-function on lambdas is " + "a C++1z extension">, InGroup; // inline asm related. let CategoryName = "Inline Assembly Issue" in { Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -1138,6 +1138,23 @@ return SourceMgr.getDiagnostics(); } +bool ASTContext::isEmptyOrContainsOnlyWarningOrIgnorableDiagnostics( + ArrayRef PartialDiags) const { + bool OnlyWarnOrIgs = true; + + DiagnosticsEngine &DE = getDiagnostics(); + for (const PartialDiagnosticAt &PD : PartialDiags) { + DiagnosticsEngine::Level DiagLevel = + DE.getDiagnosticLevel(PD.second.getDiagID(), PD.first); + if (DiagLevel != DiagnosticsEngine::Ignored && + DiagLevel != DiagnosticsEngine::Warning) { + OnlyWarnOrIgs = false; + break; + } + } + return OnlyWarnOrIgs; +} + AttrVec& ASTContext::getDeclAttrs(const Decl *D) { AttrVec *&Result = DeclAttrs[D]; if (!Result) { Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -2185,12 +2185,13 @@ Eval->IsEvaluating = false; Eval->WasEvaluated = true; - // In C++11, we have determined whether the initializer was a constant // expression as a side-effect. if (getASTContext().getLangOpts().CPlusPlus11 && !Eval->CheckedICE) { Eval->CheckedICE = true; - Eval->IsICE = Result && Notes.empty(); + Eval->IsICE = Result && + getASTContext().isEmptyOrContainsOnlyWarningOrIgnorableDiagnostics( + Notes); } return Result ? &Eval->Evaluated : nullptr; Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -4237,6 +4237,13 @@ if (!EvaluateObjectArgument(Info, ME->getBase(), ThisVal)) return false; Member = ME->getMemberDecl(); + if (const CXXConversionDecl *Conv = dyn_cast(Member)) + if (Conv->getParent()->isLambda()) { + Info.Diag(E->getExprLoc(), + !Info.Ctx.getLangOpts().CPlusPlus1z + ? diag::ext_constexpr_conversion_on_lambda_cxx1z + : diag::warn_cxx14_compat_constexpr_conversion_on_lambda); + } This = &ThisVal; HasQualifier = ME->hasQualifier(); } else if (const BinaryOperator *BE = dyn_cast(Callee)) { @@ -9622,7 +9629,7 @@ APValue Scratch; bool IsConstExpr = ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch); - if (!Diags.empty()) { + if (!Ctx.isEmptyOrContainsOnlyWarningOrIgnorableDiagnostics(Diags)) { IsConstExpr = false; if (Loc) *Loc = Diags[0].first; } else if (!IsConstExpr) { @@ -9694,7 +9701,8 @@ HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr, Args, FD->getBody(), Info, Scratch, nullptr); - return Diags.empty(); + return FD->getASTContext().isEmptyOrContainsOnlyWarningOrIgnorableDiagnostics( + Diags); } bool Expr::isPotentialConstantExprUnevaluated(Expr *E, @@ -9718,7 +9726,8 @@ APValue ResultScratch; Evaluate(ResultScratch, Info, E); - return Diags.empty(); + return FD->getASTContext().isEmptyOrContainsOnlyWarningOrIgnorableDiagnostics( + Diags); } bool Expr::tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx, Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10258,9 +10258,10 @@ } Diag(DiagLoc, diag::err_constexpr_var_requires_const_init) << var << Init->getSourceRange(); - for (unsigned I = 0, N = Notes.size(); I != N; ++I) - Diag(Notes[I].first, Notes[I].second); } + // Emit any warnings or notes. + for (unsigned I = 0, N = Notes.size(); I != N; ++I) + Diag(Notes[I].first, Notes[I].second); } else if (var->isUsableInConstantExpressions(Context)) { // Check whether the initializer of a const variable of integral or // enumeration type is an ICE now, since we can't tell whether it was Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -819,13 +819,18 @@ return; SmallVector Diags; - if (!Cond->isValueDependent() && - !Expr::isPotentialConstantExprUnevaluated(Cond, cast(D), - Diags)) { - S.Diag(Attr.getLoc(), diag::err_enable_if_never_constant_expr); - for (int I = 0, N = Diags.size(); I != N; ++I) - S.Diag(Diags[I].first, Diags[I].second); - return; + if (!Cond->isValueDependent()) { + if (!Expr::isPotentialConstantExprUnevaluated(Cond, cast(D), + Diags)) { + S.Diag(Attr.getLoc(), diag::err_enable_if_never_constant_expr); + for (int I = 0, N = Diags.size(); I != N; ++I) + S.Diag(Diags[I].first, Diags[I].second); + return; + } else { + // Emit any warnings. + for (int I = 0, N = Diags.size(); I != N; ++I) + S.Diag(Diags[I].first, Diags[I].second); + } } D->addAttr(::new (S.Context) Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -1256,11 +1256,11 @@ if (!Expr::isPotentialConstantExpr(Dcl, Diags)) { Diag(Dcl->getLocation(), diag::ext_constexpr_function_never_constant_expr) << isa(Dcl); - for (size_t I = 0, N = Diags.size(); I != N; ++I) - Diag(Diags[I].first, Diags[I].second); // Don't return false here: we allow this for compatibility in // system headers. } + for (size_t I = 0, N = Diags.size(); I != N; ++I) + Diag(Diags[I].first, Diags[I].second); return true; } Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -1263,7 +1263,7 @@ ConvTy, ConvTSI, /*isInline=*/true, /*isExplicit=*/false, - /*isConstexpr=*/false, + /*isConstexpr=*/true, CallOperator->getBody()->getLocEnd()); Conversion->setAccess(AS_public); Conversion->setImplicit(true); Index: test/SemaCXX/cxx1z-constexpr-lambdas.cpp =================================================================== --- test/SemaCXX/cxx1z-constexpr-lambdas.cpp +++ test/SemaCXX/cxx1z-constexpr-lambdas.cpp @@ -2,7 +2,9 @@ // RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s // RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fms-extensions %s // RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s +// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -Wc++14-compat %s -DCHECK_COMPATIBILITY_WARNING +#ifndef CHECK_COMPATIBILITY_WARNING namespace test_constexpr_checking { namespace ns1 { @@ -33,4 +35,17 @@ L(3); //expected-note{{non-constexpr function}} } -} // end ns test_constexpr_call \ No newline at end of file +} // end ns test_constexpr_call +#endif + +#ifdef CHECK_COMPATIBILITY_WARNING +//expected-warning@+6{{incompatible with C++ standards before C++1z}} +//expected-warning@+6{{incompatible with C++ standards before C++1z}} +#endif + +namespace ns4 { +auto L = [](auto a) { return a; }; +constexpr int (*fp1)(int) = L; +constexpr int* (*fp2)(int*) = L; + +} // end ns4 \ No newline at end of file