Skip to content

Commit d00b355

Browse files
committed
[clang][Interp] Fix CheckCallable for undefined-and-not-constexpr fns
1 parent 15495b8 commit d00b355

File tree

3 files changed

+63
-44
lines changed

3 files changed

+63
-44
lines changed

clang/lib/AST/Interp/Interp.cpp

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -579,57 +579,61 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
579579
return false;
580580
}
581581

582-
if (!F->isConstexpr() || !F->hasBody()) {
583-
const SourceLocation &Loc = S.Current->getLocation(OpPC);
584-
if (S.getLangOpts().CPlusPlus11) {
585-
const FunctionDecl *DiagDecl = F->getDecl();
582+
if (F->isConstexpr() && F->hasBody() && F->getDecl()->isConstexpr())
583+
return true;
586584

587-
// Invalid decls have been diagnosed before.
588-
if (DiagDecl->isInvalidDecl())
589-
return false;
585+
// Implicitly constexpr.
586+
if (F->isLambdaStaticInvoker())
587+
return true;
590588

591-
// If this function is not constexpr because it is an inherited
592-
// non-constexpr constructor, diagnose that directly.
593-
const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
594-
if (CD && CD->isInheritingConstructor()) {
595-
const auto *Inherited = CD->getInheritedConstructor().getConstructor();
596-
if (!Inherited->isConstexpr())
597-
DiagDecl = CD = Inherited;
598-
}
589+
const SourceLocation &Loc = S.Current->getLocation(OpPC);
590+
if (S.getLangOpts().CPlusPlus11) {
591+
const FunctionDecl *DiagDecl = F->getDecl();
592+
593+
// Invalid decls have been diagnosed before.
594+
if (DiagDecl->isInvalidDecl())
595+
return false;
596+
597+
// If this function is not constexpr because it is an inherited
598+
// non-constexpr constructor, diagnose that directly.
599+
const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
600+
if (CD && CD->isInheritingConstructor()) {
601+
const auto *Inherited = CD->getInheritedConstructor().getConstructor();
602+
if (!Inherited->isConstexpr())
603+
DiagDecl = CD = Inherited;
604+
}
599605

600-
// FIXME: If DiagDecl is an implicitly-declared special member function
601-
// or an inheriting constructor, we should be much more explicit about why
602-
// it's not constexpr.
603-
if (CD && CD->isInheritingConstructor()) {
604-
S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
606+
// FIXME: If DiagDecl is an implicitly-declared special member function
607+
// or an inheriting constructor, we should be much more explicit about why
608+
// it's not constexpr.
609+
if (CD && CD->isInheritingConstructor()) {
610+
S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
605611
<< CD->getInheritedConstructor().getConstructor()->getParent();
606-
S.Note(DiagDecl->getLocation(), diag::note_declared_at);
607-
} else {
608-
// Don't emit anything if the function isn't defined and we're checking
609-
// for a constant expression. It might be defined at the point we're
610-
// actually calling it.
611-
bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
612-
if (!DiagDecl->isDefined() && !IsExtern &&
613-
S.checkingPotentialConstantExpression())
614-
return false;
612+
S.Note(DiagDecl->getLocation(), diag::note_declared_at);
613+
} else {
614+
// Don't emit anything if the function isn't defined and we're checking
615+
// for a constant expression. It might be defined at the point we're
616+
// actually calling it.
617+
bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
618+
if (!DiagDecl->isDefined() && !IsExtern && DiagDecl->isConstexpr() &&
619+
S.checkingPotentialConstantExpression())
620+
return false;
615621

616-
// If the declaration is defined, declared 'constexpr' _and_ has a body,
617-
// the below diagnostic doesn't add anything useful.
618-
if (DiagDecl->isDefined() && DiagDecl->isConstexpr() &&
619-
DiagDecl->hasBody())
620-
return false;
622+
// If the declaration is defined, declared 'constexpr' _and_ has a body,
623+
// the below diagnostic doesn't add anything useful.
624+
if (DiagDecl->isDefined() && DiagDecl->isConstexpr() &&
625+
DiagDecl->hasBody())
626+
return false;
621627

622-
S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
628+
S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
623629
<< DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
624-
S.Note(DiagDecl->getLocation(), diag::note_declared_at);
625-
}
626-
} else {
627-
S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
630+
S.Note(DiagDecl->getLocation(), diag::note_declared_at);
628631
}
629-
return false;
632+
} else {
633+
S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
630634
}
631635

632-
return true;
636+
return false;
633637
}
634638

635639
bool CheckCallDepth(InterpState &S, CodePtr OpPC) {

clang/lib/AST/Interp/Interp.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,14 +2531,14 @@ inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
25312531
if (!CheckInvoke(S, OpPC, ThisPtr))
25322532
return false;
25332533
}
2534-
2535-
if (S.checkingPotentialConstantExpression())
2536-
return false;
25372534
}
25382535

25392536
if (!CheckCallable(S, OpPC, Func))
25402537
return false;
25412538

2539+
if (Func->hasThisPointer() && S.checkingPotentialConstantExpression())
2540+
return false;
2541+
25422542
if (!CheckCallDepth(S, OpPC))
25432543
return false;
25442544

clang/test/AST/Interp/cxx2a.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fcxx-exceptions -verify=ref,both %s
2+
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fcxx-exceptions -verify=expected,both %s -fexperimental-new-constant-interpreter
3+
4+
template <unsigned N>
5+
struct S {
6+
S() requires (N==1) = default;
7+
S() requires (N==2) {} // both-note {{declared here}}
8+
consteval S() requires (N==3) = default;
9+
};
10+
11+
consteval int aConstevalFunction() { // both-error {{consteval function never produces a constant expression}}
12+
S<2> s4; // both-note {{non-constexpr constructor 'S' cannot be used in a constant expression}}
13+
return 0;
14+
}
15+
/// We're NOT calling the above function. The diagnostics should appear anyway.

0 commit comments

Comments
 (0)