Skip to content

Commit 4099472

Browse files
authored
Merge pull request #3541 from masatake/cxx--constexpr-property
CXX: add constexpr to "properties:" field
2 parents 4beb680 + 934550a commit 4099472

File tree

9 files changed

+120
-1
lines changed

9 files changed

+120
-1
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
--sort=no
2+
--kinds-c++=*
3+
--fields=+x
4+
--fields-c++=+{properties}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
factorial input.cc /^constexpr int factorial(int n)$/;" f typeref:typename:int properties:constexpr
2+
n input.cc /^constexpr int factorial(int n)$/;" z function:factorial typeref:typename:int file:
3+
factorial_cxx14 input.cc /^constexpr int factorial_cxx14(int n)$/;" f typeref:typename:int properties:constexpr
4+
n input.cc /^constexpr int factorial_cxx14(int n)$/;" z function:factorial_cxx14 typeref:typename:int file:
5+
res input.cc /^ int res = 1;$/;" l function:factorial_cxx14 typeref:typename:int file:
6+
conststr input.cc /^class conststr$/;" c file:
7+
p input.cc /^ const char* p;$/;" m class:conststr typeref:typename:const char * file:
8+
sz input.cc /^ std::size_t sz;$/;" m class:conststr typeref:typename:std::size_t file:
9+
conststr input.cc /^ constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {}$/;" f class:conststr file: properties:constexpr
10+
a input.cc /^ constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {}$/;" z function:conststr::conststr typeref:typename:const char (&)[N] file:
11+
operator [] input.cc /^ constexpr char operator[](std::size_t n) const$/;" f class:conststr typeref:typename:char file: properties:const,constexpr
12+
n input.cc /^ constexpr char operator[](std::size_t n) const$/;" z function:conststr::operator [] typeref:typename:std::size_t file:
13+
size input.cc /^ constexpr std::size_t size() const { return sz; }$/;" f class:conststr typeref:typename:std::size_t file: properties:const,constexpr
14+
countlower input.cc /^constexpr std::size_t countlower(conststr s, std::size_t n = 0,$/;" f typeref:typename:std::size_t properties:constexpr
15+
s input.cc /^constexpr std::size_t countlower(conststr s, std::size_t n = 0,$/;" z function:countlower typeref:typename:conststr file:
16+
n input.cc /^constexpr std::size_t countlower(conststr s, std::size_t n = 0,$/;" z function:countlower typeref:typename:std::size_t file:
17+
c input.cc /^ std::size_t c = 0)$/;" z function:countlower typeref:typename:std::size_t file:
18+
constN input.cc /^struct constN$/;" s file:
19+
n input.cc /^template<int n>$/;" Z struct:constN typeref:typename:int
20+
constN input.cc /^ constN() { std::cout << n << '\\n'; }$/;" f struct:constN file:
21+
main input.cc /^int main()$/;" f typeref:typename:int
22+
out1 input.cc /^ constN<factorial(4)> out1; \/\/ computed at compile time$/;" l function:main typeref:typename:constN<factorial (4)> file:
23+
k input.cc /^ volatile int k = 8; \/\/ disallow optimization using volatile$/;" l function:main typeref:typename:volatile int file:
24+
out2 input.cc /^ constN<countlower("Hello, world!")> out2; \/\/ implicitly converted to conststr$/;" l function:main typeref:typename:constN<countlower ("Hello, world!")> file:
25+
a input.cc /^ constexpr int a[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8};$/;" l function:main typeref:typename:int[12] file: properties:constexpr
26+
length_a input.cc /^ constexpr int length_a = sizeof(a)\/sizeof(int); \/\/ std::size(a) in C++17,$/;" l function:main typeref:typename:int file: properties:constexpr
27+
i input.cc /^ for (int i = 0; i < length_a; ++i)$/;" l function:main typeref:typename:int file:
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Taken from https://en.cppreference.com/w/cpp/language/constexpr
2+
3+
#include <iostream>
4+
#include <stdexcept>
5+
6+
// C++11 constexpr functions use recursion rather than iteration
7+
constexpr int factorial(int n)
8+
{
9+
return n <= 1 ? 1 : (n * factorial(n - 1));
10+
}
11+
12+
// C++14 constexpr functions may use local variables and loops
13+
#if __cplusplus >= 201402L
14+
constexpr int factorial_cxx14(int n)
15+
{
16+
int res = 1;
17+
while (n > 1)
18+
res *= n--;
19+
return res;
20+
}
21+
#endif // C++14
22+
23+
// literal class
24+
class conststr
25+
{
26+
const char* p;
27+
std::size_t sz;
28+
public:
29+
template<std::size_t N>
30+
constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {}
31+
32+
// constexpr functions signal errors by throwing exceptions
33+
// in C++11, they must do so from the conditional operator ?:
34+
constexpr char operator[](std::size_t n) const
35+
{
36+
return n < sz ? p[n] : throw std::out_of_range("");
37+
}
38+
39+
constexpr std::size_t size() const { return sz; }
40+
};
41+
42+
// C++11 constexpr functions had to put everything in a single return statement
43+
// (C++14 doesn't have that requirement)
44+
constexpr std::size_t countlower(conststr s, std::size_t n = 0,
45+
std::size_t c = 0)
46+
{
47+
return n == s.size() ? c :
48+
'a' <= s[n] && s[n] <= 'z' ? countlower(s, n + 1, c + 1) :
49+
countlower(s, n + 1, c);
50+
}
51+
52+
// output function that requires a compile-time constant, for testing
53+
template<int n>
54+
struct constN
55+
{
56+
constN() { std::cout << n << '\n'; }
57+
};
58+
59+
int main()
60+
{
61+
std::cout << "4! = " ;
62+
constN<factorial(4)> out1; // computed at compile time
63+
64+
volatile int k = 8; // disallow optimization using volatile
65+
std::cout << k << "! = " << factorial(k) << '\n'; // computed at run time
66+
67+
std::cout << "the number of lowercase letters in \"Hello, world!\" is ";
68+
constN<countlower("Hello, world!")> out2; // implicitly converted to conststr
69+
70+
constexpr int a[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
71+
constexpr int length_a = sizeof(a)/sizeof(int); // std::size(a) in C++17,
72+
// std::ssize(a) in C++20
73+
std::cout << "array of length " << length_a << " has elements: ";
74+
for (int i = 0; i < length_a; ++i)
75+
std::cout << a[i] << " ";
76+
}

parsers/cxx/cxx_parser_block.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,8 @@ static bool cxxParserParseBlockInternal(bool bExpectClosingBracket)
637637
case CXXKeywordCONST:
638638
g_cxx.uKeywordState |= CXXParserKeywordStateSeenConst;
639639
break;
640+
case CXXKeywordCONSTEXPR:
641+
g_cxx.uKeywordState |= CXXParserKeywordStateSeenConstexpr;
640642
default:
641643
if(g_cxx.uKeywordState & CXXParserKeywordStateSeenTypedef)
642644
{

parsers/cxx/cxx_parser_function.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,6 +1729,8 @@ int cxxParserEmitFunctionTags(
17291729
uProperties |= CXXTagPropertyExtern;
17301730
if(g_cxx.uKeywordState & CXXParserKeywordStateSeenAttributeDeprecated)
17311731
uProperties |= CXXTagPropertyDeprecated;
1732+
if(g_cxx.uKeywordState & CXXParserKeywordStateSeenConstexpr)
1733+
uProperties |= CXXTagPropertyConstexpr;
17321734
if(pInfo->pSignatureConst)
17331735
uProperties |= CXXTagPropertyConst;
17341736
if(pInfo->uFlags & CXXFunctionSignatureInfoPure)

parsers/cxx/cxx_parser_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ typedef enum _CXXParserKeywordState
284284
CXXParserKeywordStateSeenAttributeDeprecated = (1 << 11),
285285
// "friend" has been seen at block level
286286
CXXParserKeywordStateSeenFriend = (1 << 12),
287+
// "constexpr" has been seen
288+
CXXParserKeywordStateSeenConstexpr = (1 << 13),
287289
} CXXParserKeywordState;
288290

289291
#define CXX_PARSER_MAXIMUM_NESTING_LEVELS 1024

parsers/cxx/cxx_parser_variable.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,8 @@ bool cxxParserExtractVariableDeclarations(CXXTokenChain * pChain,unsigned int uF
757757
// Volatile is part of the type, so we don't mark it as a property
758758
//if(g_cxx.uKeywordState & CXXParserKeywordStateSeenVolatile)
759759
// uProperties |= CXXTagPropertyVolatile;
760+
if(g_cxx.uKeywordState & CXXParserKeywordStateSeenConstexpr)
761+
uProperties |= CXXTagPropertyConstexpr;
760762

761763
pszProperties = cxxTagSetProperties(uProperties);
762764
}

parsers/cxx/cxx_tag.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ vString * cxxTagSetProperties(unsigned int uProperties)
334334
ADD_PROPERTY("scopedenum");
335335
if(uProperties & CXXTagPropertyFunctionTryBlock)
336336
ADD_PROPERTY("fntryblock");
337+
if (uProperties & CXXTagPropertyConstexpr)
338+
ADD_PROPERTY("constexpr");
337339

338340
cxxTagSetField(CXXTagFieldProperties,vStringValue(pszProperties),false);
339341

parsers/cxx/cxx_tag.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,9 @@ typedef enum _CXXTagProperty
150150
// scoped enum (C++11)
151151
CXXTagPropertyScopedEnum = (1 << 16),
152152
// function-try-block: int f() try { ... } catch { ... }
153-
CXXTagPropertyFunctionTryBlock = (1 << 17)
153+
CXXTagPropertyFunctionTryBlock = (1 << 17),
154+
// constexpr has been seen.
155+
CXXTagPropertyConstexpr = (1 << 18),
154156
} CXXTagProperty;
155157

156158
// Set the modifiers field of the tag.

0 commit comments

Comments
 (0)