Skip to content

Commit

Permalink
C++23: some more grammar changes
Browse files Browse the repository at this point in the history
- add final grammar changes for C++23
- auto(x) and auto{x} [P0849R8](https://wg21.link/P0849R8)
- duplicate attributes [P2156R1](https://wg21.link/P2156R1)
- static constexpr [P2647R1](https://wg21.link/P2647R1)
- static operator [P2589R0](https://wg21.link/P2589R0) [P1169R4](https://wg21.link/P1169R4)
- linked SonarOpenCommunity#2536
  • Loading branch information
guwirth committed Sep 2, 2024
1 parent 1136201 commit 230c5d6
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 42 deletions.
29 changes: 0 additions & 29 deletions cxx-squid/dox/diff-cpp20-cpp23_grammar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,32 +131,3 @@ d-char:
any member of the basic character set except:
u+0020 space, u+0028 left parenthesis, u+0029 right parenthesis, u+005c reverse solidus,
u+0009 character tabulation, u+000b line tabulation, u+000c form feed, and new-line

**A.5 Expressions [gram.expr]**

requirement-parameter-list:
( parameter-declaration-clause )

requirement-seq:
requirement
requirement requirement-seq

**A.7 Declarations [gram.dcl]**

elaborated-type-specifier:
class-key attribute-specifier-seqopt nested-name-specifieropt identifier
class-key simple-template-id
class-key nested-name-specifier templateopt simple-template-id
enum nested-name-specifieropt identifier

using-enum-declaration:
using enum using-enum-declarator ;

using-enum-declarator:
nested-name-specifieropt identifier
nested-name-specifieropt simple-template-id

**A.11 Templates [gram.temp]**

concept-definition:
concept concept-name attribute-specifier-seqopt = constraint-expression ;
22 changes: 13 additions & 9 deletions cxx-squid/src/main/java/org/sonar/cxx/parser/CxxGrammarImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ public enum CxxGrammarImpl implements GrammarRuleKey {
decltypeSpecifier,
placeholderTypeSpecifier,
elaboratedTypeSpecifier,
elaboratedEnumSpecifier,
enumName,
enumSpecifier,
enumHead,
Expand All @@ -176,6 +175,7 @@ public enum CxxGrammarImpl implements GrammarRuleKey {
enumeratorDefinition,
enumerator,
usingEnumDeclaration,
usingEnumDeclarator,
namespaceName,
namespaceDefinition,
namedNamespaceDefinition,
Expand Down Expand Up @@ -649,7 +649,7 @@ private static void expressions(LexerfulGrammarBuilder b) {
);

b.rule(requirementParameterList).is(
"(", b.optional(parameterDeclarationClause), ")" // C++
"(", parameterDeclarationClause, ")" // C++
);

b.rule(requirementBody).is(
Expand Down Expand Up @@ -1290,14 +1290,10 @@ private static void declarations(LexerfulGrammarBuilder b) {
b.sequence(b.optional(attributeSpecifierSeq), b.optional(nestedNameSpecifier), IDENTIFIER) // C++
)
),
elaboratedEnumSpecifier // C++
b.sequence(CxxKeyword.ENUM, b.optional(nestedNameSpecifier), IDENTIFIER) // C++
)
);

b.rule(elaboratedEnumSpecifier).is(
CxxKeyword.ENUM, b.optional(nestedNameSpecifier), IDENTIFIER // C++
);

b.rule(decltypeSpecifier).is(
CxxKeyword.DECLTYPE, "(",
b.firstOf(
Expand Down Expand Up @@ -1632,7 +1628,15 @@ private static void declarations(LexerfulGrammarBuilder b) {
);

b.rule(usingEnumDeclaration).is(
CxxKeyword.USING, elaboratedEnumSpecifier, ";"
CxxKeyword.USING, CxxKeyword.ENUM, usingEnumDeclarator, ";"
);

b.rule(usingEnumDeclarator).is(
b.optional(nestedNameSpecifier),
b.firstOf(
IDENTIFIER,
simpleTemplateId
)
);

b.rule(namespaceName).is(
Expand Down Expand Up @@ -2306,7 +2310,7 @@ private static void templates(LexerfulGrammarBuilder b) {
);

b.rule(conceptDefinition).is(
CxxKeyword.CONCEPT, conceptName, "=", constraintExpression, ";" // C++
CxxKeyword.CONCEPT, conceptName, b.optional(attributeSpecifierSeq), "=", constraintExpression, ";" // C++
);

b.rule(conceptName).is(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,6 @@ void elaboratedTypeSpecifier() {
mockRule(CxxGrammarImpl.attributeSpecifierSeq);
mockRule(CxxGrammarImpl.nestedNameSpecifier);
mockRule(CxxGrammarImpl.simpleTemplateId);
mockRule(CxxGrammarImpl.elaboratedEnumSpecifier);

assertThatParser()
.matches("classKey foo")
Expand All @@ -443,7 +442,8 @@ void elaboratedTypeSpecifier() {
.matches("classKey simpleTemplateId")
.matches("classKey nestedNameSpecifier simpleTemplateId")
.matches("classKey nestedNameSpecifier template simpleTemplateId")
.matches("elaboratedEnumSpecifier");
.matches("enum foo")
.matches("enum nestedNameSpecifier foo");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ void requirementParameterList() {
mockRule(CxxGrammarImpl.parameterDeclarationClause);

assertThatParser()
.matches("( )")
.matches("( parameterDeclarationClause )");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,11 @@ void conceptDefinition() {

mockRule(CxxGrammarImpl.conceptName);
mockRule(CxxGrammarImpl.constraintExpression);
mockRule(CxxGrammarImpl.attributeSpecifierSeq);

assertThatParser().matches("concept conceptName = constraintExpression ;");
assertThatParser()
.matches("concept conceptName = constraintExpression ;")
.matches("concept conceptName attributeSpecifierSeq = constraintExpression ;");
}

@Test
Expand Down
31 changes: 31 additions & 0 deletions cxx-squid/src/test/resources/parser/own/C++23/auto.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
void foo() {
// variable definition
auto v(x);
auto v{x};
ClassTemplate v(x);
ClassTemplate v{x};

// new expression
new auto(x);
new auto{x};
new ClassTemplate(x);
new ClassTemplate{x};
}

// function-style cast
template<typename T, typename U>
T cast1(U const &u) {
return auto(u);
}
template<typename T, typename U>
T cast2(U const &u) {
return auto{u};
}
template<typename T, typename U>
T cast3(U const &u) {
return ClassTemplate(u);
}
template<typename T, typename U>
T cast4(U const &u) {
return ClassTemplate{u};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[[gnu::sample]] [[gnu::sample]] [[gnu::hot]] [[nodiscard]]
inline int f(); // declare f with four attributes

[[gnu::sample, gnu::sample, gnu::hot, nodiscard]]
int f(); // same as above, but uses a single attr specifier that contains four attributes

[[using gnu : sample, sample, hot]] [[nodiscard]] [[gnu::sample]]
int f(); // same as above
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
char xdigit1(int n) {
static constexpr char digits[] = "0123456789abcdef";
return digits[n];
}

constexpr char xdigit2(int n) {
static constexpr char digits[] = "0123456789abcdef"; // C++23
return digits[n];
}
56 changes: 56 additions & 0 deletions cxx-squid/src/test/resources/parser/own/C++23/static-operator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// --- static operator() ---

// Overload Resolution
struct less {
static constexpr auto operator()(int i, int j) -> bool {
return i < j;
}
using P = bool( * )(int, int);
operator P() const {
return operator();
}
};

void foo() {
static_assert(less {}(1, 2));
}

// Lambdas
auto four = []() static {
return 4;
};

// Static lambdas with capture
auto under_lock = [lock = std::unique_lock(mtx)]() static {
/* do something */ ;
};

// --- static operator[] ---

template < typename T, std::size_t S > struct array: std::array < T, S > {
static constexpr inline std::size_t extent = []() -> std::size_t {
if constexpr(_is_array < T > ) {
return 1 + T::extent;
}
return 1;
}();
constexpr decltype(auto)
operator[](std::size_t idx) {
return * (this -> data() + idx);
}
constexpr decltype(auto)
operator[](std::size_t idx, convertible_to < std::size_t > auto && ...args)
requires(sizeof...(args) < extent) && (sizeof...(args) >= 1) {
typename std::array < T, S > ::reference v = * (this -> data() + idx);
return v.operator[](args...);
}
constexpr decltype(auto)
operator[](std::size_t idx) const {
return * (this -> data() + idx);
}
constexpr decltype(auto)
operator[](std::size_t idx, convertible_to < std::size_t > auto && ...args) const requires(sizeof...(args) < extent) && (sizeof...(args) >= 1) {
typename std::array < T, S > ::reference v = * (this -> data() + idx);
return v.operator[](args...);
}
};

0 comments on commit 230c5d6

Please sign in to comment.