Skip to content

Commit 11b3be1

Browse files
committed
[clang][bytecode] Don't diagnose defined functions that will have a body
But don't have one, yet. That happens for class methods, which are "defined" but have no body, hence they willHaveBody. Fixes #164995
1 parent f8b004d commit 11b3be1

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
@@ -930,14 +930,23 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
930930
if (F->isValid() && F->hasBody() && F->isConstexpr())
931931
return true;
932932

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

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

943952
// Diagnose failed assertions specially.
@@ -955,64 +964,61 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
955964
}
956965
}
957966

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

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

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

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

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

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

1007-
if (DiagDecl->getDefinition())
1008-
S.Note(DiagDecl->getDefinition()->getLocation(),
1009-
diag::note_declared_at);
1010-
else
1011-
S.Note(DiagDecl->getLocation(), diag::note_declared_at);
1012-
}
1013-
} else {
10141014
S.FFDiag(S.Current->getLocation(OpPC),
1015-
diag::note_invalid_subexpr_in_const_expr);
1015+
diag::note_constexpr_invalid_function, 1)
1016+
<< DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
1017+
1018+
if (DiagDecl->getDefinition())
1019+
S.Note(DiagDecl->getDefinition()->getLocation(), diag::note_declared_at);
1020+
else
1021+
S.Note(DiagDecl->getLocation(), diag::note_declared_at);
10161022
}
10171023

10181024
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)