From: Olivier Goffart Date: Fri, 12 Feb 2016 12:34:44 +0000 (+0000) Subject: Fix ICE with constexpr and friend functions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=26f6c2fd8a9d945be7d8f14e26ca0092abcc5ac3;p=clang Fix ICE with constexpr and friend functions Fix a crash while parsing this code: struct X { friend constexpr int foo(X*) { return 12; } static constexpr int j = foo(static_cast(nullptr)); }; Differential Revision: http://reviews.llvm.org/D16973 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@260675 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index eaa61ea5c4..739649234a 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -3736,7 +3736,8 @@ static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc, /// expression. static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, const FunctionDecl *Declaration, - const FunctionDecl *Definition) { + const FunctionDecl *Definition, + const Stmt *Body) { // Potential constant expressions can contain calls to declared, but not yet // defined, constexpr functions. if (Info.checkingPotentialConstantExpression() && !Definition && @@ -3749,7 +3750,8 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, return false; // Can we evaluate this function call? - if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl()) + if (Definition && Definition->isConstexpr() && + !Definition->isInvalidDecl() && Body) return true; if (Info.getLangOpts().CPlusPlus11) { @@ -4275,7 +4277,7 @@ public: const FunctionDecl *Definition = nullptr; Stmt *Body = FD->getBody(Definition); - if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition) || + if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body) || !HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, Info, Result, ResultSlot)) return false; @@ -5483,9 +5485,9 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { } const FunctionDecl *Definition = nullptr; - FD->getBody(Definition); + auto Body = FD->getBody(Definition); - if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition)) + if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body)) return false; // Avoid materializing a temporary for an elidable copy/move constructor. @@ -5971,9 +5973,9 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, } const FunctionDecl *Definition = nullptr; - FD->getBody(Definition); + auto Body = FD->getBody(Definition); - if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition)) + if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body)) return false; if (ZeroInit && !HadZeroInit) { diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 7b9d0150e1..47606b4f03 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -2005,3 +2005,13 @@ namespace PR24597 { constexpr int a = *f().p; constexpr int b = *g().p; } + +namespace IncompleteClass { + struct XX { + static constexpr int f(XX*) { return 1; } // expected-note {{here}} + friend constexpr int g(XX*) { return 2; } // expected-note {{here}} + + static constexpr int i = f(static_cast(nullptr)); // expected-error {{constexpr variable 'i' must be initialized by a constant expression}} expected-note {{undefined function 'f' cannot be used in a constant expression}} + static constexpr int j = g(static_cast(nullptr)); // expected-error {{constexpr variable 'j' must be initialized by a constant expression}} expected-note {{undefined function 'g' cannot be used in a constant expression}} + }; +}