Skip to content
Open
Show file tree
Hide file tree
Changes from 94 commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
cda974f
initial commit
changkhothuychung Dec 22, 2024
daf965a
Merge pull request #2 from changkhothuychung/concat
changkhothuychung Dec 22, 2024
5cfcf49
Revert "implement views::concat (P2542) "
changkhothuychung Dec 22, 2024
59c609c
Merge pull request #3 from changkhothuychung/revert-2-concat
changkhothuychung Dec 22, 2024
c59b1d3
Merge branch 'main' of https://github.com/llvm/llvm-project
changkhothuychung Dec 24, 2024
a9df861
Merge branch 'main' of https://github.com/llvm/llvm-project
changkhothuychung Jan 8, 2025
9b353b7
Merge branch 'main' of https://github.com/llvm/llvm-project
changkhothuychung Feb 9, 2025
88d8af8
Merge branch 'main' of https://github.com/llvm/llvm-project
changkhothuychung Apr 18, 2025
245f466
Merge branch 'main' of https://github.com/llvm/llvm-project
changkhothuychung Sep 26, 2025
482e25e
parsing global namespace and primitive types
changkhothuychung Oct 22, 2025
c2d6d7e
cleanup
changkhothuychung Oct 22, 2025
7c7ac79
cleanup
changkhothuychung Oct 22, 2025
61c7f94
cleanup
changkhothuychung Oct 22, 2025
78fe7c4
cleanup
changkhothuychung Oct 22, 2025
5ae0873
add dummy mangling
changkhothuychung Oct 22, 2025
4503b11
add file description
changkhothuychung Oct 22, 2025
4852569
clang format
changkhothuychung Oct 22, 2025
d3f0f70
clang format
changkhothuychung Oct 22, 2025
e93fa6e
clang format
changkhothuychung Oct 22, 2025
e845cb8
add CXXReflectExprClass to Unexposed case for now
changkhothuychung Oct 22, 2025
2d8c1cb
enum for CXXReflectExprClass
changkhothuychung Oct 22, 2025
7a331be
unused var
changkhothuychung Oct 22, 2025
340d7c0
remove wrong assertion
changkhothuychung Oct 22, 2025
7c30c5d
synthesize TypeSourceInfo before passing into ActOnReflectExpr
changkhothuychung Oct 22, 2025
08cd161
c++26 for test file instead of c++23
changkhothuychung Oct 22, 2025
258283e
change var name to reflect consuming ^^
changkhothuychung Oct 22, 2025
6b8aaf5
fix syntax
changkhothuychung Oct 22, 2025
8660059
change to use void for type placeholder
changkhothuychung Oct 22, 2025
e6fec7b
improve description of class CXXReflectExpr
changkhothuychung Oct 22, 2025
95ec04c
clang format
changkhothuychung Oct 22, 2025
8be44be
description update
changkhothuychung Oct 22, 2025
5af4ae2
Update clang/include/clang/Driver/Options.td
changkhothuychung Oct 22, 2025
13cbe6f
use OperandLoc instead
changkhothuychung Oct 22, 2025
8bd9dc3
remove IsNamespace
changkhothuychung Oct 22, 2025
dacc226
remove feature flag
changkhothuychung Oct 23, 2025
442feeb
add more test cases and rename test file
changkhothuychung Oct 23, 2025
ad7a5e6
change diagnostics description
changkhothuychung Oct 23, 2025
632c4d8
accept only built-in types for now, no other type-id yet
changkhothuychung Oct 23, 2025
ae941f2
clang format
changkhothuychung Oct 23, 2025
745cc22
fix error message in test
changkhothuychung Oct 23, 2025
f61f630
leave this function for later
changkhothuychung Oct 23, 2025
455549f
leave StmtPrinter::VisitCXXReflectExpr for later
changkhothuychung Oct 23, 2025
a7281de
update note for TODO(Reflection)
changkhothuychung Oct 23, 2025
72c191d
Update clang/include/clang/AST/ExprCXX.h
changkhothuychung Oct 24, 2025
af47462
Merge branch 'main' of https://github.com/changkhothuychung/llvm-project
changkhothuychung Oct 24, 2025
21b9784
Merge branch 'refl-parse' of https://github.com/changkhothuychung/llv…
changkhothuychung Oct 24, 2025
0de3284
clang format
changkhothuychung Oct 24, 2025
634c3dd
revert unintedned change
changkhothuychung Oct 24, 2025
dc5b7cc
remove unintended new line
changkhothuychung Oct 24, 2025
5a4efbd
add c++26 check when parsing double caret
changkhothuychung Oct 24, 2025
ceafe4b
leave note for TODO
changkhothuychung Oct 24, 2025
0ac0294
add note for TODO
changkhothuychung Oct 24, 2025
09dd041
Update clang/include/clang/AST/ExprCXX.h
changkhothuychung Oct 26, 2025
b811940
document the function declaration and change param name
changkhothuychung Oct 27, 2025
7335550
reject nested name specifier other than global namespace and add test
changkhothuychung Oct 28, 2025
ac23c88
fix comment
changkhothuychung Oct 28, 2025
bf7e78a
revert tentatie parse before returning exprerror
changkhothuychung Oct 28, 2025
f1c0088
address ^^ in binary expression
changkhothuychung Oct 28, 2025
41c3a59
fix assertion
changkhothuychung Oct 28, 2025
c213826
fix typo
changkhothuychung Oct 29, 2025
d0d0ab7
typo fix
changkhothuychung Oct 29, 2025
74150d7
Update clang/include/clang/AST/ExprCXX.h
changkhothuychung Oct 29, 2025
cde51d9
Update clang/include/clang/Driver/Options.td
changkhothuychung Oct 29, 2025
9854d9e
Update clang/lib/AST/ItaniumMangle.cpp
changkhothuychung Oct 29, 2025
d9d32ed
Update clang/lib/Parse/ParseExpr.cpp
changkhothuychung Oct 29, 2025
e8275a7
Update clang/lib/Parse/ParseReflect.cpp
changkhothuychung Oct 29, 2025
a22d917
Merge branch 'main' into refl-parse
changkhothuychung Oct 29, 2025
3b0782f
no tentative parsing for now
changkhothuychung Oct 29, 2025
fe481ca
update Parsing reflection operator
changkhothuychung Oct 29, 2025
29820dc
move test to parser
changkhothuychung Oct 29, 2025
58ac339
remove unrelated change
changkhothuychung Oct 29, 2025
8c104c4
clang format
changkhothuychung Oct 29, 2025
56997b7
Merge branch 'main' of https://github.com/llvm/llvm-project into refl…
changkhothuychung Nov 11, 2025
b38fb97
Merge branch 'refl-parse' of https://github.com/changkhothuychung/llv…
changkhothuychung Nov 11, 2025
348348e
Update clang/lib/Parse/ParseReflect.cpp
changkhothuychung Nov 11, 2025
c78e314
Update clang/lib/Parse/ParseExpr.cpp
changkhothuychung Nov 11, 2025
a623415
rename test file
changkhothuychung Nov 11, 2025
f852125
Update clang/include/clang/AST/ExprCXX.h
changkhothuychung Nov 12, 2025
e3c76a4
Update clang/include/clang/AST/ExprCXX.h
changkhothuychung Nov 12, 2025
8a1852c
Update clang/include/clang/Sema/Sema.h
changkhothuychung Nov 12, 2025
7450614
Update clang/lib/AST/ExprCXX.cpp
changkhothuychung Nov 12, 2025
8a0f646
Update clang/lib/AST/ExprCXX.cpp
changkhothuychung Nov 12, 2025
aa29b6c
Update clang/lib/AST/ExprCXX.cpp
changkhothuychung Nov 12, 2025
f135dcc
Update clang/lib/Sema/SemaExpr.cpp
changkhothuychung Nov 12, 2025
08962b5
Update clang/test/Parser/parsing-reflection.cpp
changkhothuychung Nov 12, 2025
03b9653
Update clang/test/Parser/parsing-reflection.cpp
changkhothuychung Nov 12, 2025
f8d2d8a
add TODO and fix test files
changkhothuychung Nov 12, 2025
336cb0d
Update clang/include/clang/Basic/DiagnosticParseKinds.td
changkhothuychung Nov 19, 2025
acbc699
fix comment for ^^ in binary operator context
changkhothuychung Nov 19, 2025
99950d7
add comments for operator precedence
changkhothuychung Nov 19, 2025
96280f7
make -freflection cc-1 only and only c++26 mode
changkhothuychung Nov 26, 2025
db1ad53
Merge branch 'refl-parse' of https://github.com/changkhothuychung/llv…
changkhothuychung Nov 26, 2025
7fabcaa
change scope to only parse primitive types for now
changkhothuychung Nov 29, 2025
bbe8da3
fix test
changkhothuychung Nov 29, 2025
2d65e6a
Update clang/lib/Parse/ParseReflect.cpp
changkhothuychung Dec 1, 2025
f88ba6e
Update clang/lib/Lex/Lexer.cpp
changkhothuychung Dec 1, 2025
fadde00
clang format
changkhothuychung Dec 1, 2025
b444df9
change diagnostics message
changkhothuychung Dec 1, 2025
544dc12
change from fallthrough to diag.reports for reflection mangling
changkhothuychung Dec 1, 2025
a5ad36c
Merge branch 'main' into refl-parse
changkhothuychung Dec 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/TypeSwitch.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
Expand Down Expand Up @@ -5501,6 +5502,58 @@ class BuiltinBitCastExpr final
}
};

/// Represents a C++26 reflect expression [expr.reflect]. The operand of the
/// expression is either:
/// - :: (global namespace),
/// - a reflection-name,
/// - a type-id, or
/// - an id-expression.
class CXXReflectExpr : public Expr {

// TODO(Reflection): add support for TemplateReference, NamespaceReference and
// DeclRefExpr
using operand_type = llvm::PointerUnion<const TypeLoc *>;

SourceLocation CaretCaretLoc;
operand_type Operand;

CXXReflectExpr(SourceLocation CaretCaretLoc, const TypeLoc *TL);
CXXReflectExpr(EmptyShell Empty);

public:
static CXXReflectExpr *Create(ASTContext &C, SourceLocation OperatorLoc,
TypeLoc *TL);

static CXXReflectExpr *CreateEmpty(ASTContext &C);

SourceLocation getBeginLoc() const LLVM_READONLY {
return llvm::TypeSwitch<operand_type, SourceLocation>(Operand)
.Case<const TypeLoc *>([](auto *Ptr) { return Ptr->getBeginLoc(); });
}

SourceLocation getEndLoc() const LLVM_READONLY {
return llvm::TypeSwitch<operand_type, SourceLocation>(Operand)
.Case<const TypeLoc *>([](auto *Ptr) { return Ptr->getEndLoc(); });
}

/// Returns location of the '^^'-operator.
SourceLocation getOperatorLoc() const { return CaretCaretLoc; }

child_range children() {
// TODO(Reflection)
return child_range(child_iterator(), child_iterator());
}

const_child_range children() const {
// TODO(Reflection)
return const_child_range(const_child_iterator(), const_child_iterator());
}

static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXReflectExprClass;
}
};

} // namespace clang

#endif // LLVM_CLANG_AST_EXPRCXX_H
2 changes: 2 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2883,6 +2883,8 @@ DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, {
TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
})

DEF_TRAVERSE_STMT(CXXReflectExpr, {/*TODO*/})

// These expressions all might take explicit template arguments.
// We traverse those if so. FIXME: implement these.
DEF_TRAVERSE_STMT(CXXConstructExpr, {})
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -901,4 +901,7 @@ def warn_drv_gcc_install_dir_libstdcxx : Warning<
"future releases of the clang compiler will prefer GCC installations "
"containing libstdc++ include directories; '%0' would be chosen over '%1'">,
InGroup<DiagGroup<"gcc-install-dir-libstdcxx">>;

def err_drv_reflection_requires_cxx26 : Error<
"option '%0' is only supported when compiling in C++26 mode">;
}
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1851,6 +1851,11 @@ def err_placeholder_expected_auto_or_decltype_auto : Error<
"expected 'auto' or 'decltype(auto)' after concept name">;
}

let CategoryName = "Reflection Diagnostics" in {
def err_cannot_reflect_operand : Error<
"expected reflectable entity">;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we think of better wording for this? The diagnostic doesn't really help the user to understand how to repair their code -- if they passed in something wrong, they likely don't know what a "reflectable entity" is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now this PR only supports parsing for global namespace and primitive types. If a diagnostics is hit, it could be because the operand is invalid, or it is not yet implemented. The parsing logic is incomplete, so its hard to distinguish the two's for now. I proposed I would complete the parsing logic in the next PR, so we would have a better idea how we want to provide wordings for the diagnostics.

If you have any suggestions for now, please let me know, thanks!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its probably ok to leave this really awful for now, I have no idea what it means either,, but I'm hopeful this'll improve.
DEPENDING on how long we intend this to last, we might think about saying something like, unknown or unimplemented reflectable entity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the message to unknown or unimplemented reflectable entity. Depending on how we want to scope the next PR, I can work on parsing the remaining items in reflect-expression, by then we will have a better idea how we want to have diagnostics messages in specific cases.

}

def warn_max_tokens : Warning<
"the number of preprocessor source tokens (%0) exceeds this token limit (%1)">,
InGroup<MaxTokens>, DefaultIgnore;
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ LANGOPT(BoundsSafety, 1, 0, NotCompatible, "Bounds safety extension for C")
LANGOPT(EnableLifetimeSafety, 1, 0, NotCompatible, "Experimental lifetime safety analysis for C++")

LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type")
LANGOPT(Reflection , 1, 0, NotCompatible, "C++26 Reflection")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want this as an option. IMO, we should just have this be turned on for C++26, and not enable-able for other language versions.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I (at least partially) disagree. Reflection is so experimental I think it should be an option, but one that can only be enabled in C++26 mode. Given that the feature is changing in the last few minutes of getting C++26 out the door, I think we should treat reflection like we would a TS to some degree so users can opt out of it, especially because of the potential to break code (there's still parsing ambiguities with ^^ and blocks, though far less of them than there were with ^ as the operator).


#undef LANGOPT
#undef ENUM_LANGOPT
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/StmtNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ def CoyieldExpr : StmtNode<CoroutineSuspendExpr>;
def ConceptSpecializationExpr : StmtNode<Expr>;
def RequiresExpr : StmtNode<Expr>;

// c++ 26 reflection
def CXXReflectExpr : StmtNode<Expr>;

// Obj-C Expressions.
def ObjCStringLiteral : StmtNode<Expr>;
def ObjCBoxedExpr : StmtNode<Expr>;
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ PUNCTUATOR(greatergreater, ">>")
PUNCTUATOR(greaterequal, ">=")
PUNCTUATOR(greatergreaterequal, ">>=")
PUNCTUATOR(caret, "^")
PUNCTUATOR(caretcaret, "^^")
PUNCTUATOR(caretequal, "^=")
PUNCTUATOR(pipe, "|")
PUNCTUATOR(pipepipe, "||")
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Options/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -3694,6 +3694,11 @@ defm application_extension : BoolFOption<"application-extension",
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Restrict code to those available for App Extensions">,
NegFlag<SetFalse>>;
defm reflection : BoolFOption<"reflection",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, we should decide which versions we want this enabled for, but I don't think just enabling on a command line arg is going to be our direction forward.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intentional that there are no driver changes in this PR to accept this option and consume it for the front-end?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes sense as a CC1-only option rather than a driver option. aka. the driver can say "C++26 mode? enable reflection by default", but there's still a hidden escape hatch to say -Xclang -fno-reflection if you need to. I think the frontend should reject -freflection outside of -std=c++26 (or later) modes, so this isn't a backdoor way to enable reflection in older language modes. WDYT?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no strong opinion on whether Reflection should (in the medium term) be opt-in or opt-out in C++26 mode. In the short term, it should be opt-in (and opting in via a CC1-only option is fine).

In other words, (for now) we can make it a CC1-only option that, if enabled outside of C++26, generates an error.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree completely, the default-off (opt-in) and only in C++26 mode are important to me.

I think exposing this in the driver is likely premature.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so right now its an cc1-only option, off by default, I will need to add c++26-only mode right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not exactly just a cc1 option right now. It is accepted and (mostly) ignored by the Clang driver. You may want to change that too.

As for making it C++26-only, you may be able to add a check in Clang to generate an error if the option ends up being on without C++26 being on as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hubert-reinterpretcast I need to remove ClangOption to have the driver generate errors on the flag freflection, and use ShouldParseIf<cpp26.KeyPath> for c++26 only mode, is that correct?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to remove ClangOption to have the driver generate errors on the flag freflection

Yes.

and use ShouldParseIf<cpp26.KeyPath> for c++26 only mode, is that correct?

I'm not familiar with that construct. Sorry.

LangOpts<"Reflection">, DefaultFalse,
PosFlag<SetTrue, [], [CC1Option],
"Enable C++26 reflection">,
NegFlag<SetFalse>>, ShouldParseIf<cplusplus.KeyPath>;
defm sized_deallocation : BoolFOption<"sized-deallocation",
LangOpts<"SizedDeallocation">, Default<cpp14.KeyPath>,
PosFlag<SetTrue, [], [], "Enable C++14 sized global deallocation functions">,
Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ enum class TentativeCXXTypeIdContext {
AsTemplateArgument,
InTrailingReturnType,
AsGenericSelectionArgument,
AsReflectionOperand
};

/// The kind of attribute specifier we have found.
Expand Down Expand Up @@ -5157,6 +5158,15 @@ class Parser : public CodeCompletionHandler {

///@}

//===--------------------------------------------------------------------===//
// Reflection parsing

/// ParseCXXReflectExpression - parses the operand of reflection operator
///
/// \returns on success, an expression holding the constructed CXXReflectExpr;
/// on failture, an ExprError
ExprResult ParseCXXReflectExpression();

//
//
// -------------------------------------------------------------------------
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -14736,6 +14736,11 @@ class Sema final : public SemaBase {
/// Implementations are in SemaConcept.cpp
///@{

public:
ExprResult ActOnCXXReflectExpr(SourceLocation OpLoc, TypeLoc *TL);

ExprResult BuildCXXReflectExpr(SourceLocation OperatorLoc, TypeLoc *TL);

public:
void PushSatisfactionStackEntry(const NamedDecl *D,
const llvm::FoldingSetNodeID &ID) {
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1925,6 +1925,9 @@ enum StmtCode {
EXPR_CONCEPT_SPECIALIZATION, // ConceptSpecializationExpr
EXPR_REQUIRES, // RequiresExpr

// Reflection
EXPR_REFLECT,

// CUDA
EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr

Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3730,6 +3730,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case PackIndexingExprClass:
case HLSLOutArgExprClass:
case OpenACCAsteriskSizeExprClass:
case CXXReflectExprClass:
// These never have a side-effect.
return false;

Expand Down
17 changes: 17 additions & 0 deletions clang/lib/AST/ExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,23 @@ TypeTraitExpr *TypeTraitExpr::CreateDeserialized(const ASTContext &C,
return new (Mem) TypeTraitExpr(EmptyShell(), IsStoredAsBool);
}

CXXReflectExpr::CXXReflectExpr(EmptyShell Empty)
: Expr(CXXReflectExprClass, Empty) {}

CXXReflectExpr::CXXReflectExpr(SourceLocation CaretCaretLoc, const TypeLoc *TL)
: Expr(CXXReflectExprClass, TL->getType(), VK_PRValue, OK_Ordinary),
CaretCaretLoc(CaretCaretLoc), Operand(TL) {}

CXXReflectExpr *CXXReflectExpr::Create(ASTContext &C,
SourceLocation CaretCaretLoc,
TypeLoc *TL) {
return new (C) CXXReflectExpr(CaretCaretLoc, TL);
}

CXXReflectExpr *CXXReflectExpr::CreateEmpty(ASTContext &C) {
return new (C) CXXReflectExpr(EmptyShell());
}

CUDAKernelCallExpr::CUDAKernelCallExpr(Expr *Fn, CallExpr *Config,
ArrayRef<Expr *> Args, QualType Ty,
ExprValueKind VK, SourceLocation RP,
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ExprClassification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::SourceLocExprClass:
case Expr::ConceptSpecializationExprClass:
case Expr::RequiresExprClass:
case Expr::CXXReflectExprClass:
return Cl::CL_PRValue;

case Expr::EmbedExprClass:
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20045,6 +20045,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::CXXNoexceptExprClass:
case Expr::CXXReflectExprClass:
return NoDiag();
case Expr::CallExprClass:
case Expr::CXXOperatorCallExprClass: {
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4946,6 +4946,12 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
E = cast<ConstantExpr>(E)->getSubExpr();
goto recurse;

case Expr::CXXReflectExprClass: {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we need a similar case for the Microsoft mangler?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@katzdm can you help me on this question?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@changkhothuychung Yes, absolutely; analogous changes should be made to MicrosoftMangle.cpp.

Some context: ItaniumMangle.cpp and MicrosoftMangle.cpp implement two different schemes for mangling the name of a C++ entity; the former implements the Itanium C++ ABI, whereas the latter (as far as I'm aware) does "whatever Microsoft Visual C++ does".

A few things to note here:

  1. In the Clang/P2996 fork, I at some point basically stopped updating MicrosoftMangle.cpp (for no other principled reason than laziness).
  2. Since MicrosoftMangle.cpp attempts to remain compatible with "whatever Microsoft Visual C++" does, any mangling implemented here is just guesswork (which will probably be wrong) until Microsoft implements P2996 (which will surely any day now, right? 😉) Until then, it would probably be appropriate to just issue a diagnostic and fail the build if we try to mangle a reflection with Microsoft mangling.
  3. Please note that there is an active Github issue on the Itanium ABI repository discussing mangling for reflections. Anything mangling implemented in ItaniumMangle.cpp should prefer to follow what's suggested there, rather than follow whatever random nonsense I did in the Clang/P2996 repository. If any issues are encountered, we should of course surface them on that discussion thread.

@AaronBallman - Does that all sound right to you?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AaronBallman - Does that all sound right to you?

That all sounds correct to me!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AaronBallman after looking more into this, I think we can start working on this in subsequent PRs when more facilities are available. For now I'm trying to keep the scope of this PR small to get it merged. Does that sound good to you?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooof, doing this as a 'fallthrough' is probably a mistake. We should do this as a Diags.Report (we have one for 'we dont know what to do wtih this yet`.

We should just error-out, like we do in the !NullOut situation below, but do so always.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make CXXReflectExprClass join the !NullOut situation below for now?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably just not do a fallthrough, and just copy/paste the stuff inside the !NullOpt into it.

// TODO(Reflection): implement this after introducing std::meta::info
// and add info in APValue
[[fallthrough]];
}

// FIXME: invent manglings for all these.
case Expr::BlockExprClass:
case Expr::ChooseExprClass:
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/StmtPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2566,6 +2566,11 @@ void StmtPrinter::VisitCXXUnresolvedConstructExpr(
OS << ')';
}

void StmtPrinter::VisitCXXReflectExpr(CXXReflectExpr *S) {
// TODO(Reflection): Implement this.
llvm_unreachable("not implemented yet");
}

void StmtPrinter::VisitCXXDependentScopeMemberExpr(
CXXDependentScopeMemberExpr *Node) {
if (!Node->isImplicitAccess()) {
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2175,6 +2175,11 @@ StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) {
ID.AddInteger(Hasher.CalculateHash());
}

void StmtProfiler::VisitCXXReflectExpr(const CXXReflectExpr *E) {
// TODO(Reflection): Implement this.
llvm_unreachable("not implemented yet");
}

void
StmtProfiler::VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *S) {
VisitExpr(S);
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/OperatorPrecedence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator,
case tok::pipepipe: return prec::LogicalOr;
case tok::ampamp: return prec::LogicalAnd;
case tok::pipe: return prec::InclusiveOr;
// this is for the case when ^^ appears where a binary operator is needed,
// and the first ^ is the actual binary operator,
// and the second is for a block.
case tok::caretcaret:
case tok::caret: return prec::ExclusiveOr;
case tok::amp: return prec::And;
case tok::exclaimequal:
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,11 @@ static bool FixupInvocation(CompilerInvocation &Invocation,
LangOpts.RawStringLiterals = true;
}

if (Args.hasArg(OPT_freflection) && !LangOpts.CPlusPlus26) {
Diags.Report(diag::err_drv_reflection_requires_cxx26)
<< Args.getLastArg(options::OPT_freflection)->getAsString(Args);
}

LangOpts.NamedLoops =
Args.hasFlag(OPT_fnamed_loops, OPT_fno_named_loops, LangOpts.C2y);

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Lex/Lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4348,6 +4348,9 @@ bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) {
if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::caretequal;
} else if (LangOpts.Reflection && LangOpts.CPlusPlus26 && Char == '^') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::caretcaret;
} else {
if (LangOpts.OpenCL && Char == '^')
Diag(CurPtr, diag::err_opencl_logical_exclusive_or);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Parse/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ add_clang_library(clangParse
ParseTentative.cpp
Parser.cpp
ParseOpenACC.cpp
ParseReflect.cpp

LINK_LIBS
clangAST
Expand Down
34 changes: 34 additions & 0 deletions clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,28 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
Token OpToken = Tok;
ConsumeToken();

// The reflection operator is not valid here (i.e., in the place of the
// operator token in a binary expression), so if reflection and blocks are
// enabled, we split caretcaret into two carets: the first being the binary
// operator and the second being the introducer for the block.
if (OpToken.is(tok::caretcaret)) {
assert(getLangOpts().Reflection &&
"reflection support disabled - compile with -freflection");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

messages to users in 'asserts' is weird. If we want to say something like this, we should be diagnosing.

Copy link
Contributor

@katzdm katzdm Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this should be a diagnostic - this is more of a "sanity check", since tok::caretcaret should never be lexed unless getLangOpts().Reflection is enabled.

In light of that, maybe change the assert-message. Something like:

"token '^^' can only appear with reflection enabled"

Or just omit the message.

assert(getLangOpts().Reflection);

if (getLangOpts().Blocks) {
OpToken.setKind(tok::caret);
Token Caret;
{
Caret.startToken();
Caret.setKind(tok::caret);
Caret.setLocation(Tok.getLocation());
Caret.setLength(1);
}
UnconsumeToken(OpToken);
PP.EnterToken(Caret, /*IsReinject=*/true);
return ParseRHSOfBinaryExpression(LHS, MinPrec);
}
}

// If we're potentially in a template-id, we may now be able to determine
// whether we're actually in one or not.
if (OpToken.isOneOf(tok::comma, tok::greater, tok::greatergreater,
Expand Down Expand Up @@ -1208,6 +1230,18 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand,
AllowSuffix = false;
Res = ParseUnaryExprOrTypeTraitExpression();
break;
case tok::caretcaret: {
if (!getLangOpts().Reflection) {
NotCastExpr = true;
return ExprError();
}

if (NotPrimaryExpression)
*NotPrimaryExpression = true;
AllowSuffix = false;
Res = ParseCXXReflectExpression();
break;
}
case tok::ampamp: { // unary-expression: '&&' identifier
if (NotPrimaryExpression)
*NotPrimaryExpression = true;
Expand Down
Loading