mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 11:02:04 +08:00
[clang][bytecode] Don't diagnose defined functions that will have a body (#165002)
Don't use `hasBody()`, which checks all declarations. Fixes https://github.com/llvm/llvm-project/issues/164995
This commit is contained in:
@@ -932,6 +932,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;
|
||||
@@ -939,7 +948,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.
|
||||
@@ -957,64 +966,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 this function is not constexpr because it is an inherited
|
||||
// non-constexpr constructor, diagnose that directly.
|
||||
const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
|
||||
if (CD && CD->isInheritingConstructor()) {
|
||||
const auto *Inherited = CD->getInheritedConstructor().getConstructor();
|
||||
if (!Inherited->isConstexpr())
|
||||
DiagDecl = CD = Inherited;
|
||||
}
|
||||
|
||||
// Silently reject constructors of invalid classes. The invalid class
|
||||
// has been rejected elsewhere before.
|
||||
if (CD && CD->getParent()->isInvalidDecl())
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
S.FFDiag(S.Current->getLocation(OpPC),
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
if (!S.getLangOpts().CPlusPlus11) {
|
||||
S.FFDiag(S.Current->getLocation(OpPC),
|
||||
diag::note_invalid_subexpr_in_const_expr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Invalid decls have been diagnosed before.
|
||||
if (DiagDecl->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<CXXConstructorDecl>(DiagDecl);
|
||||
if (CD && CD->isInheritingConstructor()) {
|
||||
const auto *Inherited = CD->getInheritedConstructor().getConstructor();
|
||||
if (!Inherited->isConstexpr())
|
||||
DiagDecl = CD = Inherited;
|
||||
}
|
||||
|
||||
// Silently reject constructors of invalid classes. The invalid class
|
||||
// has been rejected elsewhere before.
|
||||
if (CD && CD->getParent()->isInvalidDecl())
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
S.FFDiag(S.Current->getLocation(OpPC),
|
||||
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;
|
||||
|
||||
@@ -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<typename T> constexpr T f(T);
|
||||
template<typename T> constexpr T g(T t) {
|
||||
typedef int arr[f(T())]; // both-warning {{variable length array}} \
|
||||
// both-note {{undefined function 'f<int>'}}
|
||||
return t;
|
||||
}
|
||||
template<typename T> 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}}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user