mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-27 15:41:46 +00:00
C++11 half of r147023: In C++11, additionally eagerly instantiate:
- constexpr function template instantiations - variables of reference type - constexpr variables llvm-svn: 147031
This commit is contained in:
parent
b9ccd553fc
commit
242ad89a15
@ -1025,6 +1025,12 @@ public:
|
||||
/// \endcode
|
||||
bool extendsLifetimeOfTemporary() const;
|
||||
|
||||
/// \brief Determine whether this variable's value can be used in a
|
||||
/// constant expression, according to the relevant language standard.
|
||||
/// This only checks properties of the declaration, and does not check
|
||||
/// whether the initializer is in fact a constant expression.
|
||||
bool isUsableInConstantExpressions() const;
|
||||
|
||||
EvaluatedStmt *ensureEvaluatedStmt() const;
|
||||
|
||||
/// \brief Attempt to evaluate the value of the initializer attached to this
|
||||
|
@ -1339,6 +1339,26 @@ void VarDecl::setInit(Expr *I) {
|
||||
Init = I;
|
||||
}
|
||||
|
||||
bool VarDecl::isUsableInConstantExpressions() const {
|
||||
const LangOptions &Lang = getASTContext().getLangOptions();
|
||||
|
||||
// Only const variables can be used in constant expressions in C++. C++98 does
|
||||
// not require the variable to be non-volatile, but we consider this to be a
|
||||
// defect.
|
||||
if (!Lang.CPlusPlus ||
|
||||
!getType().isConstQualified() || getType().isVolatileQualified())
|
||||
return false;
|
||||
|
||||
// In C++, const, non-volatile variables of integral or enumeration types
|
||||
// can be used in constant expressions.
|
||||
if (getType()->isIntegralOrEnumerationType())
|
||||
return true;
|
||||
|
||||
// Additionally, in C++11, non-volatile constexpr variables and references can
|
||||
// be used in constant expressions.
|
||||
return Lang.CPlusPlus0x && (isConstexpr() || getType()->isReferenceType());
|
||||
}
|
||||
|
||||
/// Convert the initializer for this declaration to the elaborated EvaluatedStmt
|
||||
/// form, which contains extra information on the evaluated value of the
|
||||
/// initializer.
|
||||
|
@ -6544,8 +6544,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
|
||||
for (unsigned I = 0, N = Notes.size(); I != N; ++I)
|
||||
Diag(Notes[I].first, Notes[I].second);
|
||||
}
|
||||
} else if (getLangOptions().CPlusPlus && !Type.isVolatileQualified() &&
|
||||
Type.isConstQualified() && Type->isIntegralOrEnumerationType()) {
|
||||
} else if (var->isUsableInConstantExpressions()) {
|
||||
// Check whether the initializer of a const variable of integral or
|
||||
// enumeration type is an ICE now, since we can't tell whether it was
|
||||
// initialized by a constant expression if we check later.
|
||||
|
@ -9491,6 +9491,11 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
|
||||
cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass())
|
||||
PendingLocalImplicitInstantiations.push_back(std::make_pair(Function,
|
||||
Loc));
|
||||
else if (Function->getTemplateInstantiationPattern()->isConstexpr())
|
||||
// Do not defer instantiations of constexpr functions, to avoid the
|
||||
// expression evaluator needing to call back into Sema if it sees a
|
||||
// call to such a function.
|
||||
InstantiateFunctionDefinition(Loc, Function);
|
||||
else
|
||||
PendingInstantiations.push_back(std::make_pair(Function, Loc));
|
||||
}
|
||||
@ -9526,9 +9531,9 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
|
||||
// This is a modification of an existing AST node. Notify listeners.
|
||||
if (ASTMutationListener *L = getASTMutationListener())
|
||||
L->StaticDataMemberInstantiated(Var);
|
||||
QualType T = Var->getType();
|
||||
if (T.isConstQualified() && !T.isVolatileQualified() &&
|
||||
T->isIntegralOrEnumerationType())
|
||||
if (Var->isUsableInConstantExpressions())
|
||||
// Do not defer instantiations of variables which could be used in a
|
||||
// constant expression.
|
||||
InstantiateStaticDataMemberDefinition(Loc, Var);
|
||||
else
|
||||
PendingInstantiations.push_back(std::make_pair(Var, Loc));
|
||||
|
@ -68,7 +68,7 @@ struct ConstexprDtor {
|
||||
};
|
||||
|
||||
// template stuff
|
||||
template <typename T> constexpr T ft(T t) { return t; } // unexpected-note {{here}}
|
||||
template <typename T> constexpr T ft(T t) { return t; }
|
||||
template <typename T> T gt(T t) { return t; }
|
||||
struct S {
|
||||
template<typename T> constexpr T f();
|
||||
@ -89,8 +89,7 @@ template <> int S::g() const; // desired-error {{non-constexpr declaration of 'g
|
||||
template <> char S::g() { return 0; } // expected-error {{no function template matches}}
|
||||
template <> double S::g() const { return 0; } // ok
|
||||
|
||||
// FIXME: The initializer is a constant expression.
|
||||
constexpr int i3 = ft(1); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{undefined function 'ft<int>'}}
|
||||
constexpr int i3 = ft(1);
|
||||
|
||||
void test() {
|
||||
// ignore constexpr when instantiating with non-literal
|
||||
|
@ -8,16 +8,17 @@ static_assert(false, "test"); // expected-error {{test}}
|
||||
|
||||
}
|
||||
|
||||
template<typename T> constexpr T id(const T &t) { return t; } // expected-note {{here}}
|
||||
// FIXME: support templates here.
|
||||
//template<typename T> constexpr T min(const T &a, const T &b) {
|
||||
// return a < b ? a : b;
|
||||
//}
|
||||
//template<typename T> constexpr T max(const T &a, const T &b) {
|
||||
// return a < b ? b : a;
|
||||
//}
|
||||
constexpr int min(const int &a, const int &b) { return a < b ? a : b; }
|
||||
constexpr int max(const int &a, const int &b) { return a < b ? b : a; }
|
||||
typedef decltype(sizeof(char)) size_t;
|
||||
|
||||
template<typename T> constexpr T id(const T &t) { return t; }
|
||||
template<typename T> constexpr T min(const T &a, const T &b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
template<typename T> constexpr T max(const T &a, const T &b) {
|
||||
return a < b ? b : a;
|
||||
}
|
||||
template<typename T, size_t N> constexpr T *begin(T (&xs)[N]) { return xs; }
|
||||
template<typename T, size_t N> constexpr T *end(T (&xs)[N]) { return xs + N; }
|
||||
|
||||
struct MemberZero {
|
||||
constexpr int zero() { return 0; }
|
||||
@ -84,8 +85,7 @@ namespace TemplateArgumentConversion {
|
||||
template<int n> struct IntParam {};
|
||||
|
||||
using IntParam0 = IntParam<0>;
|
||||
// FIXME: This should be accepted once we implement the new ICE rules.
|
||||
using IntParam0 = IntParam<id(0)>; // expected-error {{not an integral constant expression}}
|
||||
using IntParam0 = IntParam<id(0)>;
|
||||
using IntParam0 = IntParam<MemberZero().zero>; // expected-error {{did you mean to call it with no arguments?}} expected-error {{not an integral constant expression}}
|
||||
}
|
||||
|
||||
@ -94,8 +94,7 @@ namespace CaseStatements {
|
||||
switch (n) {
|
||||
// FIXME: Produce the 'add ()' fixit for this.
|
||||
case MemberZero().zero: // desired-error {{did you mean to call it with no arguments?}} expected-error {{not an integer constant expression}} expected-note {{non-literal type '<bound member function type>'}}
|
||||
// FIXME: This should be accepted once we implement the new ICE rules.
|
||||
case id(1): // expected-error {{not an integer constant expression}} expected-note {{undefined function}}
|
||||
case id(1):
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -352,14 +351,8 @@ constexpr int strcmp_ce(const char *p, const char *q) {
|
||||
|
||||
namespace StringLiteral {
|
||||
|
||||
// FIXME: Refactor this once we support constexpr templates.
|
||||
constexpr int MangleChars(const char *p) {
|
||||
return *p + 3 * (*p ? MangleChars(p+1) : 0);
|
||||
}
|
||||
constexpr int MangleChars(const char16_t *p) {
|
||||
return *p + 3 * (*p ? MangleChars(p+1) : 0);
|
||||
}
|
||||
constexpr int MangleChars(const char32_t *p) {
|
||||
template<typename Char>
|
||||
constexpr int MangleChars(const Char *p) {
|
||||
return *p + 3 * (*p ? MangleChars(p+1) : 0);
|
||||
}
|
||||
|
||||
@ -383,9 +376,6 @@ constexpr const char *max_element(const char *a, const char *b) {
|
||||
return (a+1 >= b) ? a : max_iter(a, max_element(a+1, b));
|
||||
}
|
||||
|
||||
constexpr const char *begin(const char (&arr)[45]) { return arr; }
|
||||
constexpr const char *end(const char (&arr)[45]) { return arr + 45; }
|
||||
|
||||
constexpr char str[] = "the quick brown fox jumped over the lazy dog";
|
||||
constexpr const char *max = max_element(begin(str), end(str));
|
||||
static_assert(*max == 'z', "");
|
||||
@ -400,12 +390,10 @@ static_assert(strcmp_ce("", " ") < 0, "");
|
||||
|
||||
namespace Array {
|
||||
|
||||
// FIXME: Use templates for these once we support constexpr templates.
|
||||
constexpr int Sum(const int *begin, const int *end) {
|
||||
template<typename Iter>
|
||||
constexpr auto Sum(Iter begin, Iter end) -> decltype(+*begin) {
|
||||
return begin == end ? 0 : *begin + Sum(begin+1, end);
|
||||
}
|
||||
constexpr const int *begin(const int (&xs)[5]) { return xs; }
|
||||
constexpr const int *end(const int (&xs)[5]) { return xs + 5; }
|
||||
|
||||
constexpr int xs[] = { 1, 2, 3, 4, 5 };
|
||||
constexpr int ys[] = { 5, 4, 3, 2, 1 };
|
||||
|
Loading…
Reference in New Issue
Block a user