Skip to content

Commit 6207c5b

Browse files
committed
Implement Phase 1: Add 'custom' keyword and basic parsing support
This commit implements the core infrastructure for customizable functions: Keyword and Language Support: - Added 'custom' keyword to TokenKinds.def with KEYCUSTOMFN flag - Added CustomizableFunctions language option to LangOptions.def - Keyword is enabled with -fcustomizable-functions flag Parser Support: - Extended DeclSpec with FS_custom_specified flag and FS_customLoc - Added setFunctionSpecCustom() method to DeclSpec - Modified ParseDeclarationSpecifiers() to recognize tok::kw_custom - Parser sets custom flag when 'custom' keyword is encountered AST Support: - Added IsCustomFunction bitfield to FunctionDeclBitfields in DeclBase.h - Added isCustomFunction() and setCustomFunction() accessors to FunctionDecl - Updated NumFunctionDeclBits from 32 to 33 bits - Semantic analysis in ActOnFunctionDeclarator sets flag from DeclSpec Testing: - Added basic parser test in cxx-customizable-functions-basic.cpp - Test verifies keyword recognition and feature flag requirement At this point, the compiler can successfully parse: custom void foo() { } The keyword is recognized and the AST is properly annotated. No code generation or transformation is implemented yet (Phase 2).
1 parent ae3dc6d commit 6207c5b

File tree

9 files changed

+76
-3
lines changed

9 files changed

+76
-3
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2904,6 +2904,14 @@ class FunctionDecl : public DeclaratorDecl,
29042904
FunctionDeclBits.IsInline = I;
29052905
}
29062906

2907+
/// Determine whether the "custom" keyword was specified for this function.
2908+
bool isCustomFunction() const { return FunctionDeclBits.IsCustomFunction; }
2909+
2910+
/// Set whether the "custom" keyword was specified for this function.
2911+
void setCustomFunction(bool C = true) {
2912+
FunctionDeclBits.IsCustomFunction = C;
2913+
}
2914+
29072915
/// Determine whether the function was declared in source context
29082916
/// that requires constrained FP intrinsics
29092917
bool UsesFPIntrin() const { return FunctionDeclBits.UsesFPIntrin; }

clang/include/clang/AST/DeclBase.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1742,6 +1742,8 @@ class DeclContext {
17421742
uint64_t IsInline : 1;
17431743
LLVM_PREFERRED_TYPE(bool)
17441744
uint64_t IsInlineSpecified : 1;
1745+
LLVM_PREFERRED_TYPE(bool)
1746+
uint64_t IsCustomFunction : 1;
17451747

17461748
LLVM_PREFERRED_TYPE(bool)
17471749
uint64_t IsVirtualAsWritten : 1;
@@ -1832,7 +1834,7 @@ class DeclContext {
18321834
};
18331835

18341836
/// Number of inherited and non-inherited bits in FunctionDeclBitfields.
1835-
enum { NumFunctionDeclBits = NumDeclContextBits + 32 };
1837+
enum { NumFunctionDeclBits = NumDeclContextBits + 33 };
18361838

18371839
/// Stores the bits used by CXXConstructorDecl. If modified
18381840
/// NumCXXConstructorDeclBits and the accessor

clang/include/clang/Basic/LangOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ LANGOPT(NoMathBuiltin , 1, 0, NotCompatible, "disable math builtin functions
112112
LANGOPT(GNUAsm , 1, 1, NotCompatible, "GNU-style inline assembly")
113113
LANGOPT(Coroutines , 1, 0, NotCompatible, "C++20 coroutines")
114114
LANGOPT(CoroAlignedAllocation, 1, 0, NotCompatible, "prefer Aligned Allocation according to P2014 Option 2")
115+
LANGOPT(CustomizableFunctions, 1, 0, NotCompatible, "customizable functions with tag_invoke")
115116
LANGOPT(DllExportInlines , 1, 1, NotCompatible, "dllexported classes dllexport inline methods")
116117
LANGOPT(ExperimentalLibrary, 1, 0, NotCompatible, "enable unstable and experimental library features")
117118

clang/include/clang/Basic/TokenKinds.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
#ifndef COROUTINES_KEYWORD
3838
#define COROUTINES_KEYWORD(X) CXX20_KEYWORD(X,KEYCOROUTINES)
3939
#endif
40+
#ifndef CUSTOMFN_KEYWORD
41+
#define CUSTOMFN_KEYWORD(X) CXX20_KEYWORD(X,KEYCUSTOMFN)
42+
#endif
4043
#ifndef MODULES_KEYWORD
4144
#define MODULES_KEYWORD(X) KEYWORD(X,KEYMODULES)
4245
#endif
@@ -287,6 +290,7 @@ PUNCTUATOR(greatergreatergreater, ">>>")
287290
// which are heavily based on AltiVec
288291
// KEYBORLAND - This is a keyword if Borland extensions are enabled
289292
// KEYCOROUTINES - This is a keyword if support for C++ coroutines is enabled
293+
// KEYCUSTOMFN - This is a keyword if support for customizable functions is enabled
290294
// BOOLSUPPORT - This is a keyword if 'bool' is a built-in type
291295
// HALFSUPPORT - This is a keyword if 'half' is a built-in type
292296
// WCHARSUPPORT - This is a keyword if 'wchar_t' is a built-in type
@@ -431,6 +435,9 @@ CXX20_KEYWORD(constinit , 0)
431435
CXX20_KEYWORD(concept , 0)
432436
CXX20_KEYWORD(requires , 0)
433437

438+
// C++20 / customizable functions keyword
439+
CUSTOMFN_KEYWORD(custom)
440+
434441
// Not a CXX20_KEYWORD because it is disabled by -fno-char8_t.
435442
KEYWORD(char8_t , CHAR8SUPPORT)
436443

clang/include/clang/Sema/DeclSpec.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,8 @@ class DeclSpec {
368368
unsigned FS_virtual_specified : 1;
369369
LLVM_PREFERRED_TYPE(bool)
370370
unsigned FS_noreturn_specified : 1;
371+
LLVM_PREFERRED_TYPE(bool)
372+
unsigned FS_custom_specified : 1;
371373

372374
// friend-specifier
373375
LLVM_PREFERRED_TYPE(bool)
@@ -409,7 +411,8 @@ class DeclSpec {
409411
SourceRange TypeofParensRange;
410412
SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc,
411413
TQ_unalignedLoc;
412-
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc;
414+
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc,
415+
FS_customLoc;
413416
SourceLocation FS_explicitCloseParenLoc;
414417
SourceLocation FS_forceinlineLoc;
415418
SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
@@ -462,7 +465,8 @@ class DeclSpec {
462465
TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false),
463466
TypeQualifiers(TQ_unspecified), FS_inline_specified(false),
464467
FS_forceinline_specified(false), FS_virtual_specified(false),
465-
FS_noreturn_specified(false), FriendSpecifiedFirst(false),
468+
FS_noreturn_specified(false), FS_custom_specified(false),
469+
FriendSpecifiedFirst(false),
466470
ConstexprSpecifier(
467471
static_cast<unsigned>(ConstexprSpecKind::Unspecified)),
468472
Attrs(attrFactory), writtenBS(), ObjCQualifiers(nullptr) {}
@@ -631,6 +635,9 @@ class DeclSpec {
631635
bool isNoreturnSpecified() const { return FS_noreturn_specified; }
632636
SourceLocation getNoreturnSpecLoc() const { return FS_noreturnLoc; }
633637

638+
bool isCustomSpecified() const { return FS_custom_specified; }
639+
SourceLocation getCustomSpecLoc() const { return FS_customLoc; }
640+
634641
void ClearFunctionSpecs() {
635642
FS_inline_specified = false;
636643
FS_inlineLoc = SourceLocation();
@@ -643,6 +650,8 @@ class DeclSpec {
643650
FS_explicitCloseParenLoc = SourceLocation();
644651
FS_noreturn_specified = false;
645652
FS_noreturnLoc = SourceLocation();
653+
FS_custom_specified = false;
654+
FS_customLoc = SourceLocation();
646655
}
647656

648657
/// This method calls the passed in handler on each CVRU qual being
@@ -780,6 +789,8 @@ class DeclSpec {
780789
SourceLocation CloseParenLoc);
781790
bool setFunctionSpecNoreturn(SourceLocation Loc, const char *&PrevSpec,
782791
unsigned &DiagID);
792+
bool setFunctionSpecCustom(SourceLocation Loc, const char *&PrevSpec,
793+
unsigned &DiagID);
783794

784795
bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
785796
unsigned &DiagID);

clang/lib/Parse/ParseDecl.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4170,6 +4170,9 @@ void Parser::ParseDeclarationSpecifiers(
41704170
isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID);
41714171
}
41724172
break;
4173+
case tok::kw_custom:
4174+
isInvalid = DS.setFunctionSpecCustom(Loc, PrevSpec, DiagID);
4175+
break;
41734176
case tok::kw_explicit: {
41744177
SourceLocation ExplicitLoc = Loc;
41754178
SourceLocation CloseParenLoc;

clang/lib/Sema/DeclSpec.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,20 @@ bool DeclSpec::setFunctionSpecNoreturn(SourceLocation Loc,
10781078
return false;
10791079
}
10801080

1081+
bool DeclSpec::setFunctionSpecCustom(SourceLocation Loc,
1082+
const char *&PrevSpec,
1083+
unsigned &DiagID) {
1084+
// 'custom custom' is not allowed.
1085+
if (FS_custom_specified) {
1086+
DiagID = diag::err_duplicate_declspec;
1087+
PrevSpec = "custom";
1088+
return true;
1089+
}
1090+
FS_custom_specified = true;
1091+
FS_customLoc = Loc;
1092+
return false;
1093+
}
1094+
10811095
bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
10821096
unsigned &DiagID) {
10831097
if (isFriendSpecified()) {

clang/lib/Sema/SemaDecl.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10088,6 +10088,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
1008810088
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
1008910089
bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
1009010090
isFriend = D.getDeclSpec().isFriendSpecified();
10091+
bool isCustom = D.getDeclSpec().isCustomSpecified();
10092+
if (isCustom)
10093+
NewFD->setCustomFunction(true);
1009110094
if (ImplicitInlineCXX20 && isFriend && D.isFunctionDefinition()) {
1009210095
// Pre-C++20 [class.friend]p5
1009310096
// A function can be defined in a friend declaration of a
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %clang_cc1 -std=c++20 -fcustomizable-functions -fsyntax-only -verify %s
2+
3+
// Basic parsing of 'custom' keyword
4+
5+
// Test simple custom function
6+
custom void test1() { } // expected-no-diagnostics
7+
8+
// Test with return type
9+
custom int test2() { return 42; } // expected-no-diagnostics
10+
11+
// Test with parameters
12+
custom void test3(int x) { } // expected-no-diagnostics
13+
14+
// Test with auto parameter
15+
custom void test4(auto x) { } // expected-no-diagnostics
16+
17+
// Test in namespace
18+
namespace ns {
19+
custom void test5() { } // expected-no-diagnostics
20+
}
21+
22+
// Test without the feature flag should fail
23+
// RUN: not %clang_cc1 -std=c++20 -fno-customizable-functions -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=CHECK-NO-FEATURE
24+
// CHECK-NO-FEATURE: error: unknown type name 'custom'

0 commit comments

Comments
 (0)