Skip to content

Commit

Permalink
CXX: add constexpr to "properties:" field
Browse files Browse the repository at this point in the history
Partially close universal-ctags#3539.

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
  • Loading branch information
masatake committed Nov 19, 2022
1 parent 08fd0c4 commit 4affd42
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 1 deletion.
4 changes: 4 additions & 0 deletions Units/parser-cxx.r/properties-constexpr.d/args.ctags
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
--sort=no
--kinds-c++=*
--fields=+x
--fields-c++=+{properties}
27 changes: 27 additions & 0 deletions Units/parser-cxx.r/properties-constexpr.d/expected.tags
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
factorial input.cc /^constexpr int factorial(int n)$/;" f typeref:typename:int properties:constexpr
n input.cc /^constexpr int factorial(int n)$/;" z function:factorial typeref:typename:int file:
factorial_cxx14 input.cc /^constexpr int factorial_cxx14(int n)$/;" f typeref:typename:int properties:constexpr
n input.cc /^constexpr int factorial_cxx14(int n)$/;" z function:factorial_cxx14 typeref:typename:int file:
res input.cc /^ int res = 1;$/;" l function:factorial_cxx14 typeref:typename:int file:
conststr input.cc /^class conststr$/;" c file:
p input.cc /^ const char* p;$/;" m class:conststr typeref:typename:const char * file:
sz input.cc /^ std::size_t sz;$/;" m class:conststr typeref:typename:std::size_t file:
conststr input.cc /^ constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {}$/;" f class:conststr file: properties:constexpr
a input.cc /^ constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {}$/;" z function:conststr::conststr typeref:typename:const char (&)[N] file:
operator [] input.cc /^ constexpr char operator[](std::size_t n) const$/;" f class:conststr typeref:typename:char file: properties:const,constexpr
n input.cc /^ constexpr char operator[](std::size_t n) const$/;" z function:conststr::operator [] typeref:typename:std::size_t file:
size input.cc /^ constexpr std::size_t size() const { return sz; }$/;" f class:conststr typeref:typename:std::size_t file: properties:const,constexpr
countlower input.cc /^constexpr std::size_t countlower(conststr s, std::size_t n = 0,$/;" f typeref:typename:std::size_t properties:constexpr
s input.cc /^constexpr std::size_t countlower(conststr s, std::size_t n = 0,$/;" z function:countlower typeref:typename:conststr file:
n input.cc /^constexpr std::size_t countlower(conststr s, std::size_t n = 0,$/;" z function:countlower typeref:typename:std::size_t file:
c input.cc /^ std::size_t c = 0)$/;" z function:countlower typeref:typename:std::size_t file:
constN input.cc /^struct constN$/;" s file:
n input.cc /^template<int n>$/;" Z struct:constN typeref:typename:int
constN input.cc /^ constN() { std::cout << n << '\\n'; }$/;" f struct:constN file:
main input.cc /^int main()$/;" f typeref:typename:int
out1 input.cc /^ constN<factorial(4)> out1; \/\/ computed at compile time$/;" l function:main typeref:typename:constN<factorial (4)> file:
k input.cc /^ volatile int k = 8; \/\/ disallow optimization using volatile$/;" l function:main typeref:typename:volatile int file:
out2 input.cc /^ constN<countlower("Hello, world!")> out2; \/\/ implicitly converted to conststr$/;" l function:main typeref:typename:constN<countlower ("Hello, world!")> file:
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
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
i input.cc /^ for (int i = 0; i < length_a; ++i)$/;" l function:main typeref:typename:int file:
76 changes: 76 additions & 0 deletions Units/parser-cxx.r/properties-constexpr.d/input.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Taken from https://en.cppreference.com/w/cpp/language/constexpr

#include <iostream>
#include <stdexcept>

// C++11 constexpr functions use recursion rather than iteration
constexpr int factorial(int n)
{
return n <= 1 ? 1 : (n * factorial(n - 1));
}

// C++14 constexpr functions may use local variables and loops
#if __cplusplus >= 201402L
constexpr int factorial_cxx14(int n)
{
int res = 1;
while (n > 1)
res *= n--;
return res;
}
#endif // C++14

// literal class
class conststr
{
const char* p;
std::size_t sz;
public:
template<std::size_t N>
constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {}

// constexpr functions signal errors by throwing exceptions
// in C++11, they must do so from the conditional operator ?:
constexpr char operator[](std::size_t n) const
{
return n < sz ? p[n] : throw std::out_of_range("");
}

constexpr std::size_t size() const { return sz; }
};

// C++11 constexpr functions had to put everything in a single return statement
// (C++14 doesn't have that requirement)
constexpr std::size_t countlower(conststr s, std::size_t n = 0,
std::size_t c = 0)
{
return n == s.size() ? c :
'a' <= s[n] && s[n] <= 'z' ? countlower(s, n + 1, c + 1) :
countlower(s, n + 1, c);
}

// output function that requires a compile-time constant, for testing
template<int n>
struct constN
{
constN() { std::cout << n << '\n'; }
};

int main()
{
std::cout << "4! = " ;
constN<factorial(4)> out1; // computed at compile time

volatile int k = 8; // disallow optimization using volatile
std::cout << k << "! = " << factorial(k) << '\n'; // computed at run time

std::cout << "the number of lowercase letters in \"Hello, world!\" is ";
constN<countlower("Hello, world!")> out2; // implicitly converted to conststr

constexpr int a[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
constexpr int length_a = sizeof(a)/sizeof(int); // std::size(a) in C++17,
// std::ssize(a) in C++20
std::cout << "array of length " << length_a << " has elements: ";
for (int i = 0; i < length_a; ++i)
std::cout << a[i] << " ";
}
2 changes: 2 additions & 0 deletions parsers/cxx/cxx_parser_block.c
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,8 @@ static bool cxxParserParseBlockInternal(bool bExpectClosingBracket)
case CXXKeywordCONST:
g_cxx.uKeywordState |= CXXParserKeywordStateSeenConst;
break;
case CXXKeywordCONSTEXPR:
g_cxx.uKeywordState |= CXXParserKeywordStateSeenConstexpr;
default:
if(g_cxx.uKeywordState & CXXParserKeywordStateSeenTypedef)
{
Expand Down
2 changes: 2 additions & 0 deletions parsers/cxx/cxx_parser_function.c
Original file line number Diff line number Diff line change
Expand Up @@ -1729,6 +1729,8 @@ int cxxParserEmitFunctionTags(
uProperties |= CXXTagPropertyExtern;
if(g_cxx.uKeywordState & CXXParserKeywordStateSeenAttributeDeprecated)
uProperties |= CXXTagPropertyDeprecated;
if(g_cxx.uKeywordState & CXXParserKeywordStateSeenConstexpr)
uProperties |= CXXTagPropertyConstexpr;
if(pInfo->pSignatureConst)
uProperties |= CXXTagPropertyConst;
if(pInfo->uFlags & CXXFunctionSignatureInfoPure)
Expand Down
2 changes: 2 additions & 0 deletions parsers/cxx/cxx_parser_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,8 @@ typedef enum _CXXParserKeywordState
CXXParserKeywordStateSeenAttributeDeprecated = (1 << 11),
// "friend" has been seen at block level
CXXParserKeywordStateSeenFriend = (1 << 12),
// "constexpr" has been seen
CXXParserKeywordStateSeenConstexpr = (1 << 13),
} CXXParserKeywordState;

#define CXX_PARSER_MAXIMUM_NESTING_LEVELS 1024
Expand Down
2 changes: 2 additions & 0 deletions parsers/cxx/cxx_parser_variable.c
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,8 @@ bool cxxParserExtractVariableDeclarations(CXXTokenChain * pChain,unsigned int uF
// Volatile is part of the type, so we don't mark it as a property
//if(g_cxx.uKeywordState & CXXParserKeywordStateSeenVolatile)
// uProperties |= CXXTagPropertyVolatile;
if(g_cxx.uKeywordState & CXXParserKeywordStateSeenConstexpr)
uProperties |= CXXTagPropertyConstexpr;

pszProperties = cxxTagSetProperties(uProperties);
}
Expand Down
2 changes: 2 additions & 0 deletions parsers/cxx/cxx_tag.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,8 @@ vString * cxxTagSetProperties(unsigned int uProperties)
ADD_PROPERTY("scopedenum");
if(uProperties & CXXTagPropertyFunctionTryBlock)
ADD_PROPERTY("fntryblock");
if (uProperties & CXXTagPropertyConstexpr)
ADD_PROPERTY("constexpr");

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

Expand Down
4 changes: 3 additions & 1 deletion parsers/cxx/cxx_tag.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ typedef enum _CXXTagProperty
// scoped enum (C++11)
CXXTagPropertyScopedEnum = (1 << 16),
// function-try-block: int f() try { ... } catch { ... }
CXXTagPropertyFunctionTryBlock = (1 << 17)
CXXTagPropertyFunctionTryBlock = (1 << 17),
// constexpr hasa been seen.
CXXTagPropertyConstexpr = (1 << 18),
} CXXTagProperty;

// Set the modifiers field of the tag.
Expand Down

0 comments on commit 4affd42

Please sign in to comment.