Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 58 additions & 52 deletions clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -930,14 +930,23 @@ 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;

// 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.
Expand All @@ -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<CXXConstructorDecl>(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<CXXConstructorDecl>(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;
Expand Down
21 changes: 21 additions & 0 deletions clang/test/AST/ByteCode/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
}