diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 169a9a2c7b811..0023a2d1eed7f 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -930,6 +930,15 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { if (F->isValid() && F->hasBody() && F->isConstexpr()) return true; + const FunctionDecl *DiagDecl = F->getDecl(); + const FunctionDecl *Definition = nullptr; + DiagDecl->getBody(Definition); + + if (!Definition && S.checkingPotentialConstantExpression() && + DiagDecl->isConstexpr()) { + return false; + } + // Implicitly constexpr. if (F->isLambdaStaticInvoker()) return true; @@ -937,7 +946,7 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { // Bail out if the function declaration itself is invalid. We will // have produced a relevant diagnostic while parsing it, so just // note the problematic sub-expression. - if (F->getDecl()->isInvalidDecl()) + if (DiagDecl->isInvalidDecl()) return Invalid(S, OpPC); // Diagnose failed assertions specially. @@ -955,64 +964,61 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { } } - if (S.getLangOpts().CPlusPlus11) { - const FunctionDecl *DiagDecl = F->getDecl(); - - // Invalid decls have been diagnosed before. - if (DiagDecl->isInvalidDecl()) - return false; + if (!S.getLangOpts().CPlusPlus11) { + S.FFDiag(S.Current->getLocation(OpPC), + diag::note_invalid_subexpr_in_const_expr); + return false; + } - // If this function is not constexpr because it is an inherited - // non-constexpr constructor, diagnose that directly. - const auto *CD = dyn_cast(DiagDecl); - if (CD && CD->isInheritingConstructor()) { - const auto *Inherited = CD->getInheritedConstructor().getConstructor(); - if (!Inherited->isConstexpr()) - DiagDecl = CD = Inherited; - } + // Invalid decls have been diagnosed before. + if (DiagDecl->isInvalidDecl()) + return false; - // Silently reject constructors of invalid classes. The invalid class - // has been rejected elsewhere before. - if (CD && CD->getParent()->isInvalidDecl()) - return false; + // If this function is not constexpr because it is an inherited + // non-constexpr constructor, diagnose that directly. + const auto *CD = dyn_cast(DiagDecl); + if (CD && CD->isInheritingConstructor()) { + const auto *Inherited = CD->getInheritedConstructor().getConstructor(); + if (!Inherited->isConstexpr()) + DiagDecl = CD = Inherited; + } - // FIXME: If DiagDecl is an implicitly-declared special member function - // or an inheriting constructor, we should be much more explicit about why - // it's not constexpr. - if (CD && CD->isInheritingConstructor()) { - S.FFDiag(S.Current->getLocation(OpPC), - diag::note_constexpr_invalid_inhctor, 1) - << CD->getInheritedConstructor().getConstructor()->getParent(); - S.Note(DiagDecl->getLocation(), diag::note_declared_at); - } else { - // Don't emit anything if the function isn't defined and we're checking - // for a constant expression. It might be defined at the point we're - // actually calling it. - bool IsExtern = DiagDecl->getStorageClass() == SC_Extern; - bool IsDefined = F->isDefined(); - if (!IsDefined && !IsExtern && DiagDecl->isConstexpr() && - S.checkingPotentialConstantExpression()) - return false; + // Silently reject constructors of invalid classes. The invalid class + // has been rejected elsewhere before. + if (CD && CD->getParent()->isInvalidDecl()) + return false; - // If the declaration is defined, declared 'constexpr' _and_ has a body, - // the below diagnostic doesn't add anything useful. - if (DiagDecl->isDefined() && DiagDecl->isConstexpr() && - DiagDecl->hasBody()) - return false; + // FIXME: If DiagDecl is an implicitly-declared special member function + // or an inheriting constructor, we should be much more explicit about why + // it's not constexpr. + if (CD && CD->isInheritingConstructor()) { + S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_invalid_inhctor, + 1) + << CD->getInheritedConstructor().getConstructor()->getParent(); + S.Note(DiagDecl->getLocation(), diag::note_declared_at); + } else { + // Don't emit anything if the function isn't defined and we're checking + // for a constant expression. It might be defined at the point we're + // actually calling it. + bool IsExtern = DiagDecl->getStorageClass() == SC_Extern; + bool IsDefined = F->isDefined(); + if (!IsDefined && !IsExtern && DiagDecl->isConstexpr() && + S.checkingPotentialConstantExpression()) + return false; - S.FFDiag(S.Current->getLocation(OpPC), - diag::note_constexpr_invalid_function, 1) - << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; + // If the declaration is defined, declared 'constexpr' _and_ has a body, + // the below diagnostic doesn't add anything useful. + if (DiagDecl->isDefined() && DiagDecl->isConstexpr() && DiagDecl->hasBody()) + return false; - if (DiagDecl->getDefinition()) - S.Note(DiagDecl->getDefinition()->getLocation(), - diag::note_declared_at); - else - S.Note(DiagDecl->getLocation(), diag::note_declared_at); - } - } else { S.FFDiag(S.Current->getLocation(OpPC), - diag::note_invalid_subexpr_in_const_expr); + diag::note_constexpr_invalid_function, 1) + << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; + + if (DiagDecl->getDefinition()) + S.Note(DiagDecl->getDefinition()->getLocation(), diag::note_declared_at); + else + S.Note(DiagDecl->getLocation(), diag::note_declared_at); } return false; diff --git a/clang/test/AST/ByteCode/records.cpp b/clang/test/AST/ByteCode/records.cpp index 00218ba02bb31..83f32c97c50c7 100644 --- a/clang/test/AST/ByteCode/records.cpp +++ b/clang/test/AST/ByteCode/records.cpp @@ -1861,3 +1861,24 @@ namespace PrimitiveInitializedByInitList { } c{ 17 }; static_assert(c.b == 17, ""); } + +namespace MethodWillHaveBody { + class A { + public: + static constexpr int get_value2() { return 1 + get_value(); } + static constexpr int get_value() { return 1; } + }; + static_assert(A::get_value2() == 2, ""); + + template constexpr T f(T); + template constexpr T g(T t) { + typedef int arr[f(T())]; // both-warning {{variable length array}} \ + // both-note {{undefined function 'f'}} + return t; + } + template constexpr T f(T t) { // both-note {{declared here}} + typedef int arr[g(T())]; // both-note {{instantiation of}} + return t; + } + int n = f(0); // both-note {{instantiation of}} +}