Skip to content

Commit f29235d

Browse files
authored
[clang][bytecode] Don't diagnose defined functions that will have a body (#165002)
Don't use `hasBody()`, which checks all declarations. Fixes #164995
1 parent f80b273 commit f29235d

File tree

2 files changed

+79
-52
lines changed

2 files changed

+79
-52
lines changed

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 58 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -932,14 +932,23 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
932932
if (F->isValid() && F->hasBody() && F->isConstexpr())
933933
return true;
934934

935+
const FunctionDecl *DiagDecl = F->getDecl();
936+
const FunctionDecl *Definition = nullptr;
937+
DiagDecl->getBody(Definition);
938+
939+
if (!Definition && S.checkingPotentialConstantExpression() &&
940+
DiagDecl->isConstexpr()) {
941+
return false;
942+
}
943+
935944
// Implicitly constexpr.
936945
if (F->isLambdaStaticInvoker())
937946
return true;
938947

939948
// Bail out if the function declaration itself is invalid. We will
940949
// have produced a relevant diagnostic while parsing it, so just
941950
// note the problematic sub-expression.
942-
if (F->getDecl()->isInvalidDecl())
951+
if (DiagDecl->isInvalidDecl())
943952
return Invalid(S, OpPC);
944953

945954
// Diagnose failed assertions specially.
@@ -957,64 +966,61 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
957966
}
958967
}
959968

960-
if (S.getLangOpts().CPlusPlus11) {
961-
const FunctionDecl *DiagDecl = F->getDecl();
962-
963-
// Invalid decls have been diagnosed before.
964-
if (DiagDecl->isInvalidDecl())
965-
return false;
969+
if (!S.getLangOpts().CPlusPlus11) {
970+
S.FFDiag(S.Current->getLocation(OpPC),
971+
diag::note_invalid_subexpr_in_const_expr);
972+
return false;
973+
}
966974

967-
// If this function is not constexpr because it is an inherited
968-
// non-constexpr constructor, diagnose that directly.
969-
const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
970-
if (CD && CD->isInheritingConstructor()) {
971-
const auto *Inherited = CD->getInheritedConstructor().getConstructor();
972-
if (!Inherited->isConstexpr())
973-
DiagDecl = CD = Inherited;
974-
}
975+
// Invalid decls have been diagnosed before.
976+
if (DiagDecl->isInvalidDecl())
977+
return false;
975978

976-
// Silently reject constructors of invalid classes. The invalid class
977-
// has been rejected elsewhere before.
978-
if (CD && CD->getParent()->isInvalidDecl())
979-
return false;
979+
// If this function is not constexpr because it is an inherited
980+
// non-constexpr constructor, diagnose that directly.
981+
const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
982+
if (CD && CD->isInheritingConstructor()) {
983+
const auto *Inherited = CD->getInheritedConstructor().getConstructor();
984+
if (!Inherited->isConstexpr())
985+
DiagDecl = CD = Inherited;
986+
}
980987

981-
// FIXME: If DiagDecl is an implicitly-declared special member function
982-
// or an inheriting constructor, we should be much more explicit about why
983-
// it's not constexpr.
984-
if (CD && CD->isInheritingConstructor()) {
985-
S.FFDiag(S.Current->getLocation(OpPC),
986-
diag::note_constexpr_invalid_inhctor, 1)
987-
<< CD->getInheritedConstructor().getConstructor()->getParent();
988-
S.Note(DiagDecl->getLocation(), diag::note_declared_at);
989-
} else {
990-
// Don't emit anything if the function isn't defined and we're checking
991-
// for a constant expression. It might be defined at the point we're
992-
// actually calling it.
993-
bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
994-
bool IsDefined = F->isDefined();
995-
if (!IsDefined && !IsExtern && DiagDecl->isConstexpr() &&
996-
S.checkingPotentialConstantExpression())
997-
return false;
988+
// Silently reject constructors of invalid classes. The invalid class
989+
// has been rejected elsewhere before.
990+
if (CD && CD->getParent()->isInvalidDecl())
991+
return false;
998992

999-
// If the declaration is defined, declared 'constexpr' _and_ has a body,
1000-
// the below diagnostic doesn't add anything useful.
1001-
if (DiagDecl->isDefined() && DiagDecl->isConstexpr() &&
1002-
DiagDecl->hasBody())
1003-
return false;
993+
// FIXME: If DiagDecl is an implicitly-declared special member function
994+
// or an inheriting constructor, we should be much more explicit about why
995+
// it's not constexpr.
996+
if (CD && CD->isInheritingConstructor()) {
997+
S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_invalid_inhctor,
998+
1)
999+
<< CD->getInheritedConstructor().getConstructor()->getParent();
1000+
S.Note(DiagDecl->getLocation(), diag::note_declared_at);
1001+
} else {
1002+
// Don't emit anything if the function isn't defined and we're checking
1003+
// for a constant expression. It might be defined at the point we're
1004+
// actually calling it.
1005+
bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
1006+
bool IsDefined = F->isDefined();
1007+
if (!IsDefined && !IsExtern && DiagDecl->isConstexpr() &&
1008+
S.checkingPotentialConstantExpression())
1009+
return false;
10041010

1005-
S.FFDiag(S.Current->getLocation(OpPC),
1006-
diag::note_constexpr_invalid_function, 1)
1007-
<< DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
1011+
// If the declaration is defined, declared 'constexpr' _and_ has a body,
1012+
// the below diagnostic doesn't add anything useful.
1013+
if (DiagDecl->isDefined() && DiagDecl->isConstexpr() && DiagDecl->hasBody())
1014+
return false;
10081015

1009-
if (DiagDecl->getDefinition())
1010-
S.Note(DiagDecl->getDefinition()->getLocation(),
1011-
diag::note_declared_at);
1012-
else
1013-
S.Note(DiagDecl->getLocation(), diag::note_declared_at);
1014-
}
1015-
} else {
10161016
S.FFDiag(S.Current->getLocation(OpPC),
1017-
diag::note_invalid_subexpr_in_const_expr);
1017+
diag::note_constexpr_invalid_function, 1)
1018+
<< DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
1019+
1020+
if (DiagDecl->getDefinition())
1021+
S.Note(DiagDecl->getDefinition()->getLocation(), diag::note_declared_at);
1022+
else
1023+
S.Note(DiagDecl->getLocation(), diag::note_declared_at);
10181024
}
10191025

10201026
return false;

clang/test/AST/ByteCode/records.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,3 +1861,24 @@ namespace PrimitiveInitializedByInitList {
18611861
} c{ 17 };
18621862
static_assert(c.b == 17, "");
18631863
}
1864+
1865+
namespace MethodWillHaveBody {
1866+
class A {
1867+
public:
1868+
static constexpr int get_value2() { return 1 + get_value(); }
1869+
static constexpr int get_value() { return 1; }
1870+
};
1871+
static_assert(A::get_value2() == 2, "");
1872+
1873+
template<typename T> constexpr T f(T);
1874+
template<typename T> constexpr T g(T t) {
1875+
typedef int arr[f(T())]; // both-warning {{variable length array}} \
1876+
// both-note {{undefined function 'f<int>'}}
1877+
return t;
1878+
}
1879+
template<typename T> constexpr T f(T t) { // both-note {{declared here}}
1880+
typedef int arr[g(T())]; // both-note {{instantiation of}}
1881+
return t;
1882+
}
1883+
int n = f(0); // both-note {{instantiation of}}
1884+
}

0 commit comments

Comments
 (0)