//===-- ExprConstantMeta.cpp - Functions targeting reflections --*- C++ -*-===// // // Copyright 2025 Bloomberg Finance L.P. // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements all metafunctions from the header. // //===----------------------------------------------------------------------===// #include "clang/AST/APValue.h" #include "clang/AST/Attr.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclGroup.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/Metafunction.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Reflection.h" #include "clang/Basic/DiagnosticMetafn.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" namespace clang { using EvalFn = Metafunction::EvaluateFn; using DiagFn = Metafunction::DiagnoseFn; // ----------------------------------------------------------------------------- // P2996 Metafunction declarations // ----------------------------------------------------------------------------- static bool get_begin_enumerator_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool get_next_enumerator_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool get_ith_base_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool get_ith_template_argument_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool get_begin_member_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool get_next_member_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_structural_type(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool map_decl_to_entity(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool identifier_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool has_identifier(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool operator_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool source_location_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool type_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool parent_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool underlying_entity_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool proxied_entity_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool constant_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool object_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool template_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool substitute(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool extract(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_public(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_protected(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_private(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_virtual(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_pure_virtual(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_override(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_deleted(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_defaulted(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_explicit(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_noexcept(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_bit_field(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_enumerator(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_const(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_volatile(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_mutable_member(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_lvalue_reference_qualified(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_rvalue_reference_qualified(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool has_static_storage_duration(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool has_thread_storage_duration(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool has_automatic_storage_duration(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool has_internal_linkage(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool has_module_linkage(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool has_external_linkage(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool has_linkage(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_class_member(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_namespace_member(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_nonstatic_data_member(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_static_member(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_base(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_data_member_spec(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_namespace(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_function(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_variable(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_type(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_alias(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_entity_proxy(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_complete_type(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool has_complete_definition(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_enumerable_type(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_function_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_variable_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_class_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_alias_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_conversion_function_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_operator_function_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_literal_operator_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_constructor_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_concept(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_structured_binding(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_value(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_object(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool has_template_arguments(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool has_default_member_initializer(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_conversion_function(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_operator_function(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_literal_operator(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_constructor(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_default_constructor(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_copy_constructor(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_move_constructor(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_assignment(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_copy_assignment(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_move_assignment(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_destructor(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_special_member_function(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_user_provided(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_user_declared(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool reflect_result(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool data_member_spec(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool define_aggregate(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool offset_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool size_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool bit_offset_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool bit_size_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool alignment_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); // ----------------------------------------------------------------------------- // P3096 Metafunction declarations // ----------------------------------------------------------------------------- static bool get_ith_parameter_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool has_ellipsis_parameter(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool has_default_argument(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_explicit_object_parameter(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_function_parameter(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool return_type_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool variable_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool get_ith_annotation_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_annotation(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool annotate(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); // ========================= // Accessibility API (P3493) // ========================= static bool current_access_context(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool is_accessible(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); // =================================================== // Other bespoke functions (not proposed at this time) // =================================================== static bool is_access_specified(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); static bool reflect_invoke(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl); // ----------------------------------------------------------------------------- // Metafunction table // // Order of entries MUST be kept in sync with order of declarations in the // // header file. // ----------------------------------------------------------------------------- static constexpr Metafunction Metafunctions[] = { // Kind, MinArgs, MaxArgs, Impl // non-exposed metafunctions { Metafunction::MFRK_metaInfo, 2, 2, get_begin_enumerator_decl_of }, { Metafunction::MFRK_metaInfo, 2, 2, get_next_enumerator_decl_of }, { Metafunction::MFRK_metaInfo, 3, 3, get_ith_base_of }, { Metafunction::MFRK_metaInfo, 3, 3, get_ith_template_argument_of }, { Metafunction::MFRK_metaInfo, 2, 2, get_begin_member_decl_of }, { Metafunction::MFRK_metaInfo, 2, 2, get_next_member_decl_of }, { Metafunction::MFRK_bool, 1, 1, is_structural_type }, { Metafunction::MFRK_metaInfo, 1, 1, map_decl_to_entity }, // exposed metafunctions { Metafunction::MFRK_spliceFromArg, 4, 4, identifier_of }, { Metafunction::MFRK_bool, 1, 1, has_identifier }, { Metafunction::MFRK_sizeT, 1, 1, operator_of }, { Metafunction::MFRK_sourceLoc, 1, 1, source_location_of }, { Metafunction::MFRK_metaInfo, 1, 1, type_of }, { Metafunction::MFRK_metaInfo, 1, 1, parent_of }, { Metafunction::MFRK_metaInfo, 1, 1, underlying_entity_of }, { Metafunction::MFRK_metaInfo, 1, 1, proxied_entity_of }, { Metafunction::MFRK_metaInfo, 1, 1, object_of }, { Metafunction::MFRK_metaInfo, 1, 1, constant_of }, { Metafunction::MFRK_metaInfo, 1, 1, template_of }, { Metafunction::MFRK_metaInfo, 4, 4, substitute }, { Metafunction::MFRK_spliceFromArg, 2, 2, extract }, { Metafunction::MFRK_bool, 1, 1, is_public }, { Metafunction::MFRK_bool, 1, 1, is_protected }, { Metafunction::MFRK_bool, 1, 1, is_private }, { Metafunction::MFRK_bool, 1, 1, is_virtual }, { Metafunction::MFRK_bool, 1, 1, is_pure_virtual }, { Metafunction::MFRK_bool, 1, 1, is_override }, { Metafunction::MFRK_bool, 1, 1, is_deleted }, { Metafunction::MFRK_bool, 1, 1, is_defaulted }, { Metafunction::MFRK_bool, 1, 1, is_explicit }, { Metafunction::MFRK_bool, 1, 1, is_noexcept }, { Metafunction::MFRK_bool, 1, 1, is_bit_field }, { Metafunction::MFRK_bool, 1, 1, is_enumerator }, { Metafunction::MFRK_bool, 1, 1, is_const }, { Metafunction::MFRK_bool, 1, 1, is_volatile }, { Metafunction::MFRK_bool, 1, 1, is_mutable_member }, { Metafunction::MFRK_bool, 1, 1, is_lvalue_reference_qualified }, { Metafunction::MFRK_bool, 1, 1, is_rvalue_reference_qualified }, { Metafunction::MFRK_bool, 1, 1, has_static_storage_duration }, { Metafunction::MFRK_bool, 1, 1, has_thread_storage_duration }, { Metafunction::MFRK_bool, 1, 1, has_automatic_storage_duration }, { Metafunction::MFRK_bool, 1, 1, has_internal_linkage }, { Metafunction::MFRK_bool, 1, 1, has_module_linkage }, { Metafunction::MFRK_bool, 1, 1, has_external_linkage }, { Metafunction::MFRK_bool, 1, 1, has_linkage }, { Metafunction::MFRK_bool, 1, 1, is_class_member }, { Metafunction::MFRK_bool, 1, 1, is_namespace_member }, { Metafunction::MFRK_bool, 1, 1, is_nonstatic_data_member }, { Metafunction::MFRK_bool, 1, 1, is_static_member }, { Metafunction::MFRK_bool, 1, 1, is_base }, { Metafunction::MFRK_bool, 1, 1, is_data_member_spec }, { Metafunction::MFRK_bool, 1, 1, is_namespace }, { Metafunction::MFRK_bool, 1, 1, is_function }, { Metafunction::MFRK_bool, 1, 1, is_variable }, { Metafunction::MFRK_bool, 1, 1, is_type }, { Metafunction::MFRK_bool, 1, 1, is_alias }, { Metafunction::MFRK_bool, 1, 1, is_entity_proxy }, { Metafunction::MFRK_bool, 1, 1, is_complete_type }, { Metafunction::MFRK_bool, 1, 1, has_complete_definition }, { Metafunction::MFRK_bool, 1, 1, is_enumerable_type }, { Metafunction::MFRK_bool, 1, 1, is_template }, { Metafunction::MFRK_bool, 1, 1, is_function_template }, { Metafunction::MFRK_bool, 1, 1, is_variable_template }, { Metafunction::MFRK_bool, 1, 1, is_class_template }, { Metafunction::MFRK_bool, 1, 1, is_alias_template }, { Metafunction::MFRK_bool, 1, 1, is_conversion_function_template }, { Metafunction::MFRK_bool, 1, 1, is_operator_function_template }, { Metafunction::MFRK_bool, 1, 1, is_literal_operator_template }, { Metafunction::MFRK_bool, 1, 1, is_constructor_template }, { Metafunction::MFRK_bool, 1, 1, is_concept }, { Metafunction::MFRK_bool, 1, 1, is_structured_binding }, { Metafunction::MFRK_bool, 1, 1, is_value }, { Metafunction::MFRK_bool, 1, 1, is_object }, { Metafunction::MFRK_bool, 1, 1, has_template_arguments }, { Metafunction::MFRK_bool, 1, 1, has_default_member_initializer }, { Metafunction::MFRK_bool, 1, 1, is_conversion_function }, { Metafunction::MFRK_bool, 1, 1, is_operator_function }, { Metafunction::MFRK_bool, 1, 1, is_literal_operator }, { Metafunction::MFRK_bool, 1, 1, is_constructor }, { Metafunction::MFRK_bool, 1, 1, is_default_constructor }, { Metafunction::MFRK_bool, 1, 1, is_copy_constructor }, { Metafunction::MFRK_bool, 1, 1, is_move_constructor }, { Metafunction::MFRK_bool, 1, 1, is_assignment }, { Metafunction::MFRK_bool, 1, 1, is_copy_assignment }, { Metafunction::MFRK_bool, 1, 1, is_move_assignment }, { Metafunction::MFRK_bool, 1, 1, is_destructor }, { Metafunction::MFRK_bool, 1, 1, is_special_member_function }, { Metafunction::MFRK_bool, 1, 1, is_user_provided }, { Metafunction::MFRK_bool, 1, 1, is_user_declared }, { Metafunction::MFRK_metaInfo, 2, 2, reflect_result }, { Metafunction::MFRK_metaInfo, 10, 10, data_member_spec }, { Metafunction::MFRK_metaInfo, 3, 3, define_aggregate }, { Metafunction::MFRK_spliceFromArg, 2, 2, offset_of }, { Metafunction::MFRK_sizeT, 1, 1, size_of }, { Metafunction::MFRK_spliceFromArg, 2, 2, bit_offset_of }, { Metafunction::MFRK_sizeT, 1, 1, bit_size_of }, { Metafunction::MFRK_sizeT, 1, 1, alignment_of }, // P3096 metafunction extensions { Metafunction::MFRK_metaInfo, 3, 3, get_ith_parameter_of }, { Metafunction::MFRK_bool, 1, 1, has_ellipsis_parameter }, { Metafunction::MFRK_bool, 1, 1, has_default_argument }, { Metafunction::MFRK_bool, 1, 1, is_explicit_object_parameter }, { Metafunction::MFRK_bool, 1, 1, is_function_parameter }, { Metafunction::MFRK_metaInfo, 1, 1, return_type_of }, { Metafunction::MFRK_metaInfo, 1, 1, variable_of }, // P3394 annotation metafunction extensions { Metafunction::MFRK_metaInfo, 3, 3, get_ith_annotation_of }, { Metafunction::MFRK_bool, 1, 1, is_annotation }, { Metafunction::MFRK_metaInfo, 2, 2, annotate }, // P3493 accessibility extensions { Metafunction::MFRK_metaInfo, 0, 0, current_access_context }, { Metafunction::MFRK_bool, 3, 3, is_accessible }, // Other bespoke functions (not proposed at this time) { Metafunction::MFRK_bool, 1, 1, is_access_specified }, { Metafunction::MFRK_metaInfo, 5, 5, reflect_invoke }, }; constexpr const unsigned NumMetafunctions = sizeof(Metafunctions) / sizeof(Metafunction); // ----------------------------------------------------------------------------- // class Metafunction implementation // ----------------------------------------------------------------------------- bool Metafunction::evaluate(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) const { return ImplFn(Result, C, Meta, Evaluator, Diagnoser, AllowInjection, ResultTy, Range, Args, ContainingDecl); } bool Metafunction::Lookup(unsigned ID, const Metafunction *&result) { if (ID >= NumMetafunctions) return true; result = &Metafunctions[ID]; return false; } // ----------------------------------------------------------------------------- // Metafunction helper functions // ----------------------------------------------------------------------------- static APValue makeBool(ASTContext &C, bool B) { return APValue(C.MakeIntValue(B, C.BoolTy)); } static APValue makeReflection(std::nullptr_t) { return APValue(ReflectionKind::Null, nullptr); } static APValue makeReflection(QualType QT) { return APValue(ReflectionKind::Type, QT.getAsOpaquePtr()); } static APValue makeReflection(Decl *D) { if (isa(D) || isa(D) || isa(D)) return APValue(ReflectionKind::Namespace, D); else if (isa(D)) return APValue(ReflectionKind::Template, D); else if (isa(D)) return APValue(ReflectionKind::EntityProxy, D); else if (isa(D)) return APValue(ReflectionKind::Parameter, D); return APValue(ReflectionKind::Declaration, D); } static APValue makeReflection(TemplateName TName) { return APValue(ReflectionKind::Template, TName.getAsVoidPointer()); } static APValue makeReflection(CXXBaseSpecifier *Base) { return APValue(ReflectionKind::BaseSpecifier, Base); } static APValue makeReflection(TagDataMemberSpec *TDMS) { return APValue(ReflectionKind::DataMemberSpec, TDMS); } static APValue makeReflection(CXX26AnnotationAttr *A) { return APValue(ReflectionKind::Annotation, A); } static Expr *makeStrLiteral(StringRef Str, ASTContext &C, bool Utf8) { QualType ConstCharTy = (Utf8 ? C.Char8Ty : C.CharTy).withConst(); // Get the type for 'const char[Str.size()]'. QualType StrLitTy = C.getConstantArrayType(ConstCharTy, llvm::APInt(32, Str.size() + 1), nullptr, ArraySizeModifier::Normal, 0); // Create a string literal having type 'const char [Str.size()]'. StringLiteralKind SLK = Utf8 ? StringLiteralKind::UTF8 : StringLiteralKind::Ordinary; return StringLiteral::Create(C, Str, SLK, false, StrLitTy, SourceLocation{}); } static bool SetAndSucceed(APValue &Out, const APValue &Result) { Out = Result; return false; } static TemplateName findTemplateOfDecl(const Decl *D) { TemplateDecl *TDecl = nullptr; if (const auto *FD = dyn_cast(D)) { if (FunctionTemplateSpecializationInfo *Info = FD->getTemplateSpecializationInfo()) TDecl = Info->getTemplate(); } else if (const auto *VD = dyn_cast(D)) { if (const auto *P = VD->getTemplateInstantiationPattern()) VD = P; TDecl = VD->getDescribedVarTemplate(); } assert(!isa(D) && "use findTemplateOfType instead"); return TDecl ? TemplateName(TDecl) : TemplateName(); } static TemplateName findTemplateOfType(QualType QT) { // If it's an ElaboratedType, get the underlying NamedType. if (const ElaboratedType *ET = dyn_cast(QT)) QT = ET->getNamedType(); if (auto *TST = dyn_cast(QT)) { TemplateName TName = TST->getTemplateName(); if (TName.getKind() == TemplateName::QualifiedTemplate) TName = TName.getAsQualifiedTemplateName()->getUnderlyingTemplate(); return TName; } if (auto *CXXRD = QT->getAsCXXRecordDecl()) if (auto *CTSD = dyn_cast(CXXRD)) return TemplateName(CTSD->getSpecializedTemplate()); return TemplateName(); } static void getTemplateName(std::string &Result, ASTContext &C, TemplateName TName) { PrintingPolicy PP = C.getPrintingPolicy(); { llvm::raw_string_ostream NameOut(Result); TName.print(NameOut, PP, TemplateName::Qualified::None); } } static void getDeclName(std::string &Result, ASTContext &C, Decl *D) { if (TemplateName TName = findTemplateOfDecl(D); !TName.isNull()) return getTemplateName(Result, C, TName); PrintingPolicy PP = C.getPrintingPolicy(); { llvm::raw_string_ostream NameOut(Result); if (auto *ND = dyn_cast(D); ND && !isa(D)) ND->printName(NameOut, PP); } } static bool getParameterName(ParmVarDecl *PVD, std::string &Out) { // Parameters instantiated from function parameter packs are not considered // to have identifiers. if (auto STTPT = dyn_cast(PVD->getType()); STTPT && STTPT->getPackIndex()) return true; unsigned ParamIdx = PVD->getFunctionScopeIndex(); // TODO(P2996): This will crash if we're in the trailing requires-clause of // a function declaration, since the DeclContext is not the function but the // TranslationUnitDecl. FunctionDecl *FD = cast(PVD->getDeclContext()); FD = FD->getMostRecentDecl(); PVD = FD->getParamDecl(ParamIdx); bool Consistent = true; StringRef FirstNameSeen = PVD->getName(); while (PVD) { FD = cast(PVD->getDeclContext()); FD = FD->getPreviousDecl(); if (!FD) { Out = FirstNameSeen; return true; } PVD = FD->getParamDecl(ParamIdx); assert(PVD); if (IdentifierInfo *II = PVD->getIdentifier()) { if (FirstNameSeen.empty()) { FirstNameSeen = II->getName(); } else if (II->getName() != FirstNameSeen) { Consistent = false; break; } } } Out = FirstNameSeen; return Consistent; } static ParmVarDecl *getMostRecentParmVarDecl(ParmVarDecl *PVD) { // TODO(P2996): This will crash if we're in the trailing requires-clause of // a function declaration, since the DeclContext is not the function but the // TranslationUnitDecl. FunctionDecl *FD = cast(PVD->getDeclContext()); FD = FD->getMostRecentDecl(); return FD->getParamDecl(PVD->getFunctionScopeIndex()); } static NamedDecl *findTypeDecl(QualType QT) { // If it's an ElaboratedType, get the underlying NamedType. if (const ElaboratedType *ET = dyn_cast(QT)) QT = ET->getNamedType(); // Get the type's declaration. NamedDecl *D = nullptr; if (auto *TDT = dyn_cast(QT)) D = TDT->getDecl(); else if (auto *UT = dyn_cast(QT)) D = UT->getFoundDecl(); else if (auto *TD = QT->getAsTagDecl()) return TD; else if (auto *TT = dyn_cast(QT)) D = TT->getDecl(); else if (auto *UUTD = dyn_cast(QT)) D = UUTD->getDecl(); else if (auto *TS = dyn_cast(QT)) { if (auto *CTD = dyn_cast( TS->getTemplateName().getAsTemplateDecl())) { void *InsertPos; D = CTD->findSpecialization(TS->template_arguments(), InsertPos); } } else if (auto *STTP = dyn_cast(QT)) D = findTypeDecl(STTP->getReplacementType()); else if (auto *ICNT = dyn_cast(QT)) D = ICNT->getDecl(); else if (auto *DTT = dyn_cast(QT)) D = findTypeDecl(DTT->getUnderlyingType()); return D; } static bool findTypeDeclLoc(APValue &Result, ASTContext &C, EvalFn Evaluator, QualType ResultTy, QualType QT) { // If it's an ElaboratedType, get the underlying NamedType. if (const ElaboratedType *ET = dyn_cast(QT)) QT = ET->getNamedType(); // Get the type's declaration. NamedDecl *D = const_cast(findTypeDecl(QT)); SourceLocExpr *SLE = new (C) SourceLocExpr(C, SourceLocIdentKind::SourceLocStruct, ResultTy, D ? D->getLocation() : SourceLocation(), SourceLocation(), D ? D->getDeclContext() : nullptr); return !Evaluator(Result, SLE, true); } static bool findDeclLoc(APValue &Result, ASTContext &C, EvalFn Evaluator, QualType ResultTy, Decl *D) { SourceLocExpr *SLE = new (C) SourceLocExpr(C, SourceLocIdentKind::SourceLocStruct, ResultTy, D ? D->getLocation() : SourceLocation(), SourceLocation(), D ? D->getDeclContext() : nullptr); return !Evaluator(Result, SLE, true); } static bool findBaseSpecLoc(APValue &Result, ASTContext &C, EvalFn Evaluator, QualType ResultTy, CXXBaseSpecifier *B) { SourceLocExpr *SLE = new (C) SourceLocExpr(C, SourceLocIdentKind::SourceLocStruct, ResultTy, B->getBeginLoc(), SourceLocation(), B->getDerived()); return !Evaluator(Result, SLE, true); } static bool findAnnotLoc(APValue &Result, ASTContext &C, EvalFn Evaluator, QualType ResultTy, CXX26AnnotationAttr *A) { SourceLocExpr *SLE = new (C) SourceLocExpr(C, SourceLocIdentKind::SourceLocStruct, ResultTy, A->getEqLoc(), SourceLocation(), nullptr); return !Evaluator(Result, SLE, true); } static QualType desugarType(QualType QT, bool UnwrapAliases, bool DropCV, bool DropRefs) { bool IsConst = QT.isConstQualified(); bool IsVolatile = QT.isVolatileQualified(); while (true) { QT = QualType(QT.getTypePtr(), 0); if (const ElaboratedType *ET = dyn_cast(QT)) QT = ET->getNamedType(); else if (auto *TDT = dyn_cast(QT); TDT && UnwrapAliases) QT = TDT->desugar(); else if (auto *UT = dyn_cast(QT); TDT && UnwrapAliases) QT = UT->desugar(); else if (auto *TST = dyn_cast(QT); TST && UnwrapAliases && TST->isTypeAlias()) QT = TST->getAliasedType(); else if (auto *AT = dyn_cast(QT)) QT = AT->desugar(); else if (auto *RT = dyn_cast(QT); RT && DropRefs) QT = RT->getPointeeType(); else if (auto *STTP = dyn_cast(QT)) QT = STTP->getReplacementType(); else if (auto *RST = dyn_cast(QT)) QT = RST->desugar(); else break; } if (!DropCV) { if (IsConst) QT = QT.withConst(); if (IsVolatile) QT = QT.withVolatile(); } return QT; } static bool isTypeAlias(QualType QT) { // If it's an ElaboratedType, get the underlying NamedType. if (const ElaboratedType *ET = dyn_cast(QT)) QT = ET->getNamedType(); // If it's a TypedefType, it's an alias. return QT->isTypedefNameType(); } static void expandTemplateArgPacks(ArrayRef Args, SmallVectorImpl &Out) { for (const TemplateArgument &Arg : Args) if (Arg.getKind() == TemplateArgument::Pack) for (const TemplateArgument &TA : Arg.getPackAsArray()) Out.push_back(TA); else Out.push_back(Arg); } bool getTemplateArgumentsFromType(QualType QT, SmallVectorImpl &Out) { // Obtain the template arguments from the Type* representation if (auto asTmplSpecialization = QT->getAs()) expandTemplateArgPacks(asTmplSpecialization->template_arguments(), Out); else if (auto DTST = QT->getAs()) expandTemplateArgPacks(DTST->template_arguments(), Out); else if (auto *CTSD = dyn_cast_or_null( QT->getAsRecordDecl())) expandTemplateArgPacks(CTSD->getTemplateArgs().asArray(), Out); else return true; return false; } bool getTemplateArgumentsFromDecl(Decl* D, SmallVectorImpl &Out) { if (auto FD = dyn_cast(D)) { if (auto templArgs = FD->getTemplateSpecializationArgs()) { expandTemplateArgPacks(templArgs->asArray(), Out); return false; } } else if (auto VTSD = dyn_cast(D)) { expandTemplateArgPacks(VTSD->getTemplateArgs().asArray(), Out); return false; } return true; } static APValue getNthTemplateArgument(ASTContext &C, ArrayRef templateArgs, EvalFn Evaluator, APValue Sentinel, size_t Idx) { if (Idx >= templateArgs.size()) return Sentinel; const auto& templArgument = templateArgs[Idx]; switch (templArgument.getKind()) { case TemplateArgument::Type: return makeReflection(templArgument.getAsType()); case TemplateArgument::Expression: { Expr *TExpr = templArgument.getAsExpr(); APValue ArgResult; bool success = Evaluator(ArgResult, TExpr, !TExpr->isLValue()); assert(success); return ArgResult.Lift(TExpr->getType()); } case TemplateArgument::Template: { TemplateName TName = templArgument.getAsTemplate(); if (TName.getKind() == TemplateName::QualifiedTemplate) TName = TName.getAsQualifiedTemplateName()->getUnderlyingTemplate(); return makeReflection(TName); } case TemplateArgument::Declaration: return makeReflection(templArgument.getAsDecl()); case TemplateArgument::NullPtr: { APValue NullPtrValue((ValueDecl *)nullptr, CharUnits::fromQuantity(C.getTargetNullPointerValue( templArgument.getNullPtrType())), APValue::NoLValuePath(), /*IsNullPtr=*/true); return NullPtrValue.Lift(templArgument.getNullPtrType()); } case TemplateArgument::StructuralValue: { APValue SV = templArgument.getAsStructuralValue(); return SV.Lift(templArgument.getStructuralValueType()); } case TemplateArgument::Integral: { APValue IV(templArgument.getAsIntegral()); return IV.Lift(templArgument.getIntegralType()); } case TemplateArgument::Pack: llvm_unreachable("Packs should be expanded before calling this"); // Could not get a test case to hit one of the below case TemplateArgument::Null: llvm_unreachable("TemplateArgument::Null not supported"); case TemplateArgument::TemplateExpansion: llvm_unreachable("TemplateArgument::TemplateExpansion not supported"); } llvm_unreachable("Unknown template argument type"); } static bool isTemplateSpecialization(QualType QT) { if (isa(QT) || isa(QT)) return false; return isa(QT) || isa(QT) || isa_and_nonnull( QT->getAsCXXRecordDecl()); } static size_t getBitOffsetOfField(ASTContext &C, const FieldDecl *FD) { const RecordDecl *Parent = FD->getParent(); assert(Parent && "no parent for field!"); const ASTRecordLayout &Layout = C.getASTRecordLayout(Parent); return Layout.getFieldOffset(FD->getFieldIndex()); } static size_t getOffsetOfBase(ASTContext &C, const CXXBaseSpecifier *Base) { const CXXRecordDecl *Derived = Base->getDerived(); assert(Derived && "no parent for field!"); const ASTRecordLayout &Layout = C.getASTRecordLayout(Derived); QualType BaseQT = Base->getType(); BaseQT = desugarType(BaseQT, /*UnwrapAliases=*/true, /*DropCV=*/false, /*DropRefs=*/false); CXXRecordDecl *RD = BaseQT->getAsCXXRecordDecl(); assert(RD && "base isn't a record type?"); if (Base->isVirtual()) return Layout.getVBaseClassOffset(RD).getQuantity(); else return Layout.getBaseClassOffset(RD).getQuantity(); } static bool ensureDeclared(ASTContext &C, QualType QT, SourceLocation SpecLoc) { // If it's an ElaboratedType, get the underlying NamedType. if (const ElaboratedType *ET = dyn_cast(QT)) QT = ET->getNamedType(); // Get the type's declaration. if (auto *TS = dyn_cast(QT)) { if (auto *CTD = dyn_cast( TS->getTemplateName().getAsTemplateDecl())) { void *InsertPos; if (!CTD->findSpecialization(TS->template_arguments(), InsertPos)) { ClassTemplateSpecializationDecl *D = ClassTemplateSpecializationDecl::Create( C, CTD->getTemplatedDecl()->getTagKind(), CTD->getDeclContext(), SpecLoc, SpecLoc, CTD, TS->template_arguments(), false, nullptr); if (!D) return false; CTD->AddSpecialization(D, InsertPos); } } } return true; } static bool isReflectableDecl(MetaActions &Meta, ASTContext &C, Decl *D) { assert(D && "null declaration"); if (D != D->getCanonicalDecl()) { Decl *First = nullptr; for (Decl *I = D->getMostRecentDecl(); I; I = I->getPreviousDecl()) if (I->getLexicalDeclContext() == D->getLexicalDeclContext()) First = I; if (D != First) return false; } if (D->isLocalExternDecl()) return false; if (isa(D)) return true; if (!isa(D)) return false; if (isa(D) && !C.getLangOpts().EntityProxyReflection) return false; if (auto *Class = dyn_cast(D)) if (Class->isInjectedClassName() || Class->isLambda()) return false; if (auto *FD = dyn_cast(D)) { for (auto *R = FD->getMostRecentDecl(); R; R = R->getPreviousDecl()) { if (!R->getDeclaredReturnType()->isUndeducedType() && Meta.HasSatisfiedConstraints(R)) return true; } return false; } if (isa(D)) return false; return D->getCanonicalDecl() == D; } /// Filter non-reflectable members. static Decl *findIterableMember(MetaActions &Meta, ASTContext &C, Decl *D, bool Inclusive) { if (!D) return D; if (Inclusive) { if (isReflectableDecl(Meta, C, D)) return D; // Handle the case where the first Decl is a LinkageSpecDecl. if (auto *LSDecl = dyn_cast_or_null(D)) { Decl *RecD = findIterableMember(Meta, C, *LSDecl->decls_begin(), true); if (RecD) return RecD; } } do { DeclContext *DC = D->getDeclContext(); // note: SemanticDC if (D->getLexicalDeclContext() == DC) { // Get the next declaration in the DeclContext. // // Explicit specializations of templates are created with the DeclContext // of the template from which they're instantiated, but they end up in the // DeclContext within which they're declared. We therefore skip over any // declarations whose DeclContext is different from the previous Decl; // otherwise, we may inadvertently break the chain of redeclarations in // difficult to predit ways. do { D = D->getNextDeclInContext(); } while (D && D->getDeclContext() != DC); // In the case of namespaces, walk the redeclaration chain. if (auto *NSDecl = dyn_cast(DC)) { while (!D && NSDecl) { NSDecl = NSDecl->getPreviousDecl(); D = NSDecl ? *NSDecl->decls_begin() : nullptr; } if (!D) { auto *Canonical = cast(DC->getPrimaryContext()); D = Canonical->getLastMultDCSemaDecl(); } } } else { D = D->getPrevMultDCDeclInSemaContext(); } // We need to recursively descend into LinkageSpecDecls to iterate over the // members declared therein (e.g., `extern "C"` blocks). if (auto *LSDecl = dyn_cast_or_null(D)) { Decl *RecD = findIterableMember(Meta, C, *LSDecl->decls_begin(), true); if (RecD) return RecD; } // Pop back out of a recursively entered LinkageSpecDecl. if (!D && isa(DC)) return findIterableMember(Meta, C, cast(DC), false); } while (D && !isReflectableDecl(Meta, C, D)); return D; } unsigned parentOf(APValue &Result, Decl *D) { if (!D) return diag::metafn_parent_of_undeclared; if (auto *FD = dyn_cast(D); FD && FD->isExternC()) return diag::metafn_parent_of_extern_c; else if (auto *VD = dyn_cast(D); VD && VD->isExternC()) return diag::metafn_parent_of_extern_c; auto *DC = D->getDeclContext(); while (DC && !isa(DC) && !isa(DC) && !isa(DC) && !isa(DC) && !isa(DC)) DC = DC->getParent(); assert(DC); if (auto *RD = dyn_cast(DC)) return SetAndSucceed(Result, makeReflection(QualType(RD->getTypeForDecl(), 0))); return SetAndSucceed(Result, makeReflection(cast(DC))); } bool isSpecialMember(FunctionDecl *FD) { bool IsSpecial = false; if (const auto *MD = dyn_cast(FD)) { IsSpecial = (isa(MD) || MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()); if (auto *CtorD = dyn_cast(MD)) IsSpecial = IsSpecial || (CtorD->isDefaultConstructor() || CtorD->isCopyConstructor() || CtorD->isMoveConstructor()); } return IsSpecial; } static bool isFunctionOrMethodNoexcept(const QualType QT) { const Type* T = QT.getTypePtr(); if (T->isFunctionProtoType()) { // This covers (virtual) methods & functions const auto *FPT = T->getAs(); switch (FPT->getExceptionSpecType()) { case EST_BasicNoexcept: case EST_NoexceptTrue: return true; default: return false; } } return false; } static bool isConstQualifiedType(QualType QT) { bool result = QT.isConstQualified(); if (auto *FPT = dyn_cast(QT)) result |= FPT->isConst(); return result; } static bool isVolatileQualifiedType(QualType QT) { bool result = QT.isVolatileQualified(); if (auto *FPT = dyn_cast(QT)) result |= FPT->isVolatile(); return result; } QualType ComputeResultType(QualType ExprTy, const APValue &V) { SplitQualType SQT; if (V.isLValue() && !ExprTy->isPointerType() && !V.getLValueBase().isNull()) { SQT = V.getLValueBase().getType().split(); for (auto p = V.getLValuePath().begin(); p != V.getLValuePath().end(); ++p) { const Decl *D = V.getLValuePath().back().getAsBaseOrMember().getPointer(); if (D) { // base or member case if (auto *VD = dyn_cast(D)) { QualType QT = VD->getType(); SQT.Ty = QT.getTypePtr(); if (QT.isConstQualified()) SQT.Quals.addConst(); if (QT.isVolatileQualified()) SQT.Quals.addVolatile(); continue; } else if (auto *TD = dyn_cast(D)) { SQT.Ty = TD->getTypeForDecl(); continue; } llvm_unreachable("unknown lvalue path kind"); } else { // array case QualType QT = cast(SQT.Ty)->getElementType(); SQT.Ty = QT.getTypePtr(); if (QT.isConstQualified()) SQT.Quals.addConst(); if (QT.isVolatileQualified()) SQT.Quals.addVolatile(); } } return QualType(SQT.Ty, SQT.Quals.getAsOpaqueValue()); } return desugarType(ExprTy, /*UnwrapAliases=*/true, /*DropCV=*/!ExprTy->isRecordType(), /*DropRefs=*/true); } static APValue MaybeUnproxy(ASTContext &C, APValue RV, bool Dealias = true) { assert(RV.isReflection()); if (!RV.isReflectedEntityProxy()) return RV; NamedDecl *ND = RV.getReflectedEntityProxy()->getTargetDecl(); ND = cast(ND->getCanonicalDecl()); if (auto *T = dyn_cast(ND)) { QualType QT = C.getTypeDeclType(T); if (Dealias) QT = desugarType(QT, /*UnwrapAlias=*/true, /*DropCV=*/false, /*DropRefs=*/false); return APValue(ReflectionKind::Type, QT.getAsOpaquePtr()); } else if (auto *T = dyn_cast(ND)) { return APValue(ReflectionKind::Template, T); } return APValue(ReflectionKind::Declaration, ND); } // ----------------------------------------------------------------------------- // Diagnostic helper function // ----------------------------------------------------------------------------- StringRef DescriptionOf(APValue RV, bool Granular = true) { switch (RV.getReflectionKind()) { case ReflectionKind::Null: return "a null reflection"; case ReflectionKind::Type: if (isTypeAlias(RV.getReflectedType())) return "type alias"; else return "a type"; case ReflectionKind::Object: return "an object"; case ReflectionKind::Value: return "a value"; case ReflectionKind::Declaration: { ValueDecl *D = RV.getReflectedDecl(); switch (D->getDeclName().getNameKind()) { case DeclarationName::CXXConstructorName: return "a constructor"; case DeclarationName::CXXDestructorName: return "a destuctor"; case DeclarationName::CXXConversionFunctionName: return "a conversion function"; case DeclarationName::CXXOperatorName: return "an operator function"; case DeclarationName::CXXLiteralOperatorName: return "a literal operator"; default: break; } if (auto *FD = dyn_cast(D)) { if (FD->isUnnamedBitField()) return "an unnamed bit-field"; else if (FD->isBitField()) return "a bit-field"; return "a non-static data member"; } else if (isa(D)) return "function parameter"; else if (isa(D)) return "a variable"; else if (isa(D)) return "a structured binding"; else if (isa(D)) return "a function"; else if (isa(D)) return "a enumerator"; llvm_unreachable("unhandled declaration kind"); } case ReflectionKind::Template: { TemplateDecl *TD = RV.getReflectedTemplate().getAsTemplateDecl(); switch (TD->getDeclName().getNameKind()) { case DeclarationName::CXXConstructorName: return "a constructor template"; case DeclarationName::CXXDestructorName: return "a destuctor template"; case DeclarationName::CXXConversionFunctionName: return "a conversion function template"; case DeclarationName::CXXOperatorName: return "an operator function template"; case DeclarationName::CXXLiteralOperatorName: return "a literal operator template"; default: break; } if (isa(TD)) return "a function template"; else if (isa(TD)) return "a class template"; else if (isa(TD)) return "an alias template"; else if (isa(TD)) return "a variable template"; else if (isa(TD)) return "a concept"; llvm_unreachable("unhandled template kind"); } case ReflectionKind::Namespace: { Decl *D = RV.getReflectedNamespace(); if (isa(D)) return "the global namespace"; else if (isa(D)) return "a namespace alias"; else if (isa(D)) return "a namespace"; llvm_unreachable("unhandled namespace kind"); } case ReflectionKind::EntityProxy: { return "an entity proxy"; } case ReflectionKind::BaseSpecifier: { return "a base class specifier"; } case ReflectionKind::Parameter: { return "a parameter"; } case ReflectionKind::DataMemberSpec: { return "a description of a non-static data member"; } case ReflectionKind::Annotation: { return "an annotation"; } } } bool DiagnoseReflectionKind(DiagFn Diagnoser, SourceRange Range, StringRef Expected, StringRef Instead = "") { if (!Instead.empty()) Diagnoser(Range.getBegin(), diag::metafn_expected_reflection_of_but_got) << Expected << Instead << Range; else Diagnoser(Range.getBegin(), diag::metafn_expected_reflection_of) << Expected << Range; return true; } // ----------------------------------------------------------------------------- // Metafunction implementations // ----------------------------------------------------------------------------- bool get_begin_enumerator_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; APValue Sentinel; if (!Evaluator(Sentinel, Args[1], true)) return true; assert(Sentinel.isReflectedType()); switch (RV.getReflectionKind()) { case ReflectionKind::Type: { Decl *D = findTypeDecl(RV.getReflectedType()); if (auto enumDecl = dyn_cast_or_null(D)) { if (auto itr = enumDecl->enumerator_begin(); itr != enumDecl->enumerator_end()) { return SetAndSucceed(Result, makeReflection(*itr)); } return SetAndSucceed(Result, Sentinel); } return DiagnoseReflectionKind(Diagnoser, Range, "an enum type"); } case ReflectionKind::Null: case ReflectionKind::Declaration: case ReflectionKind::Template: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: { return DiagnoseReflectionKind(Diagnoser, Range, "an enum type", DescriptionOf(RV)); } } llvm_unreachable("unknown reflection kind"); } bool get_next_enumerator_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; APValue Sentinel; if (!Evaluator(Sentinel, Args[1], true)) return true; assert(Sentinel.isReflectedType()); switch (RV.getReflectionKind()) { case ReflectionKind::Declaration: { Decl *currEnumConstDecl = RV.getReflectedDecl(); if(auto nextEnumConstDecl = currEnumConstDecl->getNextDeclInContext()) { return SetAndSucceed(Result, makeReflection(nextEnumConstDecl)); } return SetAndSucceed(Result, Sentinel); } case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Template: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::Parameter: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: { llvm_unreachable("should have failed in 'get_begin_enumerator_decl_of'"); } } llvm_unreachable("unknown reflection kind"); } bool get_ith_base_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; APValue Sentinel; if (!Evaluator(Sentinel, Args[1], true)) return true; assert(Sentinel.isReflectedType()); APValue Idx; if (!Evaluator(Idx, Args[2], true)) return true; size_t idx = Idx.getInt().getExtValue(); switch (RV.getReflectionKind()) { case ReflectionKind::Type: { QualType QT = RV.getReflectedType(); QT = desugarType(QT, /*UnwrapAliases=*/true, /*DropCV=*/false, /*DropRefs=*/false); Decl *typeDecl = findTypeDecl(QT); if (auto cxxRecordDecl = dyn_cast_or_null(typeDecl)) { Meta.EnsureInstantiated(typeDecl, Range); if (RV.getReflectedType()->isIncompleteType()) return Diagnoser(Range.getBegin(), diag::metafn_cannot_introspect_type) << 0 << 0 << Range; auto numBases = cxxRecordDecl->getNumBases(); if (idx >= numBases) return SetAndSucceed(Result, Sentinel); // the unqualified base class CXXBaseSpecifier *baseClassItr = cxxRecordDecl->bases_begin() + idx; return SetAndSucceed(Result, makeReflection(baseClassItr)); } return Diagnoser(Range.getBegin(), diag::metafn_cannot_introspect_type) << 0 << 1 << Range; } case ReflectionKind::Null: case ReflectionKind::Declaration: case ReflectionKind::Template: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::Parameter: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return DiagnoseReflectionKind(Diagnoser, Range, "a class type", DescriptionOf(RV)); } llvm_unreachable("unknown reflection kind"); } bool get_ith_template_argument_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; APValue Sentinel; if (!Evaluator(Sentinel, Args[1], true)) return true; assert(Sentinel.isReflectedType()); APValue Idx; if (!Evaluator(Idx, Args[2], true)) return true; size_t idx = Idx.getInt().getExtValue(); switch (RV.getReflectionKind()) { case ReflectionKind::Type: { SmallVector TArgs; if (getTemplateArgumentsFromType(RV.getReflectedType(), TArgs)) return DiagnoseReflectionKind(Diagnoser, Range, "a template specialization"); APValue R = getNthTemplateArgument(C, TArgs, Evaluator, Sentinel, idx); if (R.isReflectedDecl()) R = APValue(APValue::LValueBase{R.getReflectedDecl()}, CharUnits::Zero(), {}, false, false).Lift(QualType{}); return SetAndSucceed(Result, R); } case ReflectionKind::Declaration: { SmallVector TArgs; if (getTemplateArgumentsFromDecl(RV.getReflectedDecl(), TArgs)) return DiagnoseReflectionKind(Diagnoser, Range, "a template specialization"); APValue R = getNthTemplateArgument(C, TArgs, Evaluator, Sentinel, idx); if (R.isReflectedDecl() && !isa(R.getReflectedDecl())) R = APValue(APValue::LValueBase{R.getReflectedDecl()}, CharUnits::Zero(), {}, false, false).Lift(QualType{}); return SetAndSucceed(Result, R); } case ReflectionKind::Null: case ReflectionKind::Template: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::Parameter: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return DiagnoseReflectionKind(Diagnoser, Range, "a template specialization", DescriptionOf(RV)); } llvm_unreachable("unknown reflection kind"); } bool get_begin_member_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(ResultTy == C.MetaInfoTy); assert(Args[0]->getType()->isReflectionType()); APValue RV; if (!Evaluator(RV, Args[0], true)) { return true; } assert(Args[1]->getType()->isReflectionType()); APValue Sentinel; if (!Evaluator(Sentinel, Args[1], true)) return true; assert(Sentinel.isReflectedType()); switch (RV.getReflectionKind()) { case ReflectionKind::Type: { QualType QT = RV.getReflectedType(); if (isTypeAlias(QT)) QT = desugarType(QT, /*UnwrapAliases=*/true, /*DropCV=*/false, /*DropRefs=*/false); if (isa(QT)) { Diagnoser(Range.getBegin(), diag::metafn_cannot_introspect_type) << 1 << 1 << Range; return Diagnoser(Range.getBegin(), diag::metafn_members_of_enum) << Range; } ensureDeclared(C, QT, Range.getBegin()); Decl *typeDecl = findTypeDecl(QT); if (!typeDecl) return true; if (!Meta.EnsureInstantiated(typeDecl, Range)) return true; if (QT->isIncompleteType()) return true; // NOTE(P2996): Uncomment to allow 'members_of' within member // specification. /* if (auto *TD = dyn_cast(typeDecl); !TD || !TD->isBeingDefined()) return true; */ if (auto *CXXRD = dyn_cast(typeDecl)) Meta.EnsureDeclarationOfImplicitMembers(CXXRD); DeclContext *declContext = dyn_cast(typeDecl); assert(declContext && "no DeclContext?"); Decl* beginMember = findIterableMember(Meta, C, *declContext->decls_begin(), true); if (!beginMember) return SetAndSucceed(Result, Sentinel); return SetAndSucceed(Result, APValue(ReflectionKind::Declaration, beginMember)); } case ReflectionKind::Namespace: { Decl *NS = RV.getReflectedNamespace(); if (auto *A = dyn_cast(NS)) NS = A->getNamespace(); DeclContext *DC = cast(NS->getMostRecentDecl()); Decl *beginMember = findIterableMember(Meta, C, *DC->decls_begin(), true); if (!beginMember) return SetAndSucceed(Result, Sentinel); return SetAndSucceed(Result, APValue(ReflectionKind::Declaration, beginMember)); } case ReflectionKind::Null: case ReflectionKind::Declaration: case ReflectionKind::EntityProxy: case ReflectionKind::Parameter: case ReflectionKind::Template: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return true; } llvm_unreachable("unknown reflection kind"); } bool get_next_member_decl_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(ResultTy == C.MetaInfoTy); assert(Args[0]->getType()->isReflectionType()); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; assert(Args[1]->getType()->isReflectionType()); APValue Sentinel; if (!Evaluator(Sentinel, Args[1], true)) return true; assert(Sentinel.isReflectedType()); if (Decl *Next = findIterableMember(Meta, C, RV.getReflectedDecl(), false)) return SetAndSucceed(Result, APValue(ReflectionKind::Declaration, Next)); return SetAndSucceed(Result, Sentinel); } bool is_structural_type(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; auto result = false; if (RV.isReflectedType()) { const QualType QT = RV.getReflectedType(); const Type* T = QT.getTypePtr(); result = T->isStructuralType(); } return SetAndSucceed(Result, makeBool(C, result)); } bool map_decl_to_entity(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(ResultTy == C.MetaInfoTy); assert(Args[0]->getType()->isReflectionType()); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; Decl *D = RV.getReflectedDecl(); if (auto *TyDecl = dyn_cast(D)) { QualType QT = C.getTypeDeclType(TyDecl); return SetAndSucceed(Result, makeReflection(QT)); } return SetAndSucceed(Result, makeReflection(D)); } bool identifier_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); APValue RV; if (!Evaluator(RV, Args[1], true)) return true; bool IsUtf8; { APValue Scratch; if (!Evaluator(Scratch, Args[2], true)) return true; IsUtf8 = Scratch.getInt().getBoolValue(); } bool EnforceConsistent; { APValue Scratch; if (!Evaluator(Scratch, Args[3], true)) return true; EnforceConsistent = Scratch.getInt().getBoolValue(); } RV = MaybeUnproxy(C, RV, /*Dealias=*/false); std::string Name; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { QualType QT = RV.getReflectedType(); if (isTemplateSpecialization(QT)) return Diagnoser(Range.getBegin(), diag::metafn_name_is_not_identifier) << 0 << Range; if (auto *D = findTypeDecl(QT)) if (auto *ND = dyn_cast(D); ND && ND->getIdentifier()) Name = ND->getIdentifier()->getName(); break; } case ReflectionKind::Declaration: { if (auto *ND = dyn_cast(RV.getReflectedDecl())) { if (!findTemplateOfDecl(ND).isNull()) return Diagnoser(Range.getBegin(), diag::metafn_name_is_not_identifier) << 0 << Range; else if (isa(ND)) return Diagnoser(Range.getBegin(), diag::metafn_name_is_not_identifier) << 1 << Range; else if (isa(ND)) return Diagnoser(Range.getBegin(), diag::metafn_name_is_not_identifier) << 2 << Range; else if (ND->getDeclName().getNameKind() == DeclarationName::CXXOperatorName) return Diagnoser(Range.getBegin(), diag::metafn_name_is_not_identifier) << 3 << Range; else if (ND->getDeclName().getNameKind() == DeclarationName::CXXConversionFunctionName) return Diagnoser(Range.getBegin(), diag::metafn_name_is_not_identifier) << 4 << Range; if (auto *II = ND->getIdentifier()) Name = II->getName(); else if (auto *II = ND->getDeclName().getCXXLiteralIdentifier()) Name = II->getName(); } break; } case ReflectionKind::Parameter: { bool ConsistentName = getParameterName(RV.getReflectedParameter(), Name); if (EnforceConsistent && !ConsistentName) { return Diagnoser(Range.getBegin(), diag::metafn_inconsistent_name) << DescriptionOf(RV) << Range; } break; } case ReflectionKind::Template: { const TemplateDecl *TD = RV.getReflectedTemplate().getAsTemplateDecl(); if (auto *FTD = dyn_cast(TD)) { if (isa(FTD->getTemplatedDecl())) return Diagnoser(Range.getBegin(), diag::metafn_name_is_not_identifier) << 5 << Range; else if (FTD->getDeclName().getNameKind() == DeclarationName::CXXOperatorName) return Diagnoser(Range.getBegin(), diag::metafn_name_is_not_identifier) << 6 << Range; else if (FTD->getDeclName().getNameKind() == DeclarationName::CXXConversionFunctionName) return Diagnoser(Range.getBegin(), diag::metafn_name_is_not_identifier) << 7 << Range; } if (auto *II = TD->getIdentifier()) Name = II->getName(); else if (auto *II = TD->getDeclName().getCXXLiteralIdentifier()) Name = II->getName(); break; } case ReflectionKind::Namespace: { if (isa(RV.getReflectedNamespace())) return Diagnoser(Range.getBegin(), diag::metafn_name_of_unnamed_singleton) << 1 << Range; getDeclName(Name, C, RV.getReflectedNamespace()); break; } case ReflectionKind::DataMemberSpec: { TagDataMemberSpec *TDMS = RV.getReflectedDataMemberSpec(); if (TDMS->Name) Name = *TDMS->Name; break; } case ReflectionKind::Null: return Diagnoser(Range.getBegin(), diag::metafn_name_of_unnamed_singleton) << 0 << Range; case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::BaseSpecifier: case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_have_name) << DescriptionOf(RV) << Range; case ReflectionKind::EntityProxy: llvm_unreachable("proxies should already have been unwrapped"); } if (Name.empty()) return Diagnoser(Range.getBegin(), diag::metafn_anonymous_entity) << DescriptionOf(RV) << Range; Expr *StrLit = makeStrLiteral(Name, C, IsUtf8); APValue::LValuePathEntry Path[1] = {APValue::LValuePathEntry::ArrayIndex(0)}; return SetAndSucceed(Result, APValue(StrLit, CharUnits::Zero(), Path, false)); } bool has_identifier(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; RV = MaybeUnproxy(C, RV, /*Dealias=*/false); bool HasIdentifier = false; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { QualType QT = RV.getReflectedType(); if (isTemplateSpecialization(QT)) break; if (auto *D = findTypeDecl(QT)) if (auto *ND = dyn_cast(D); ND && ND->getIdentifier()) HasIdentifier = (ND->getIdentifier() != nullptr); break; } case ReflectionKind::Parameter: { auto *PVD = RV.getReflectedParameter(); std::string Name; bool Consistent = getParameterName(PVD, Name); HasIdentifier = Consistent && !Name.empty(); break; } case ReflectionKind::Declaration: { auto *D = RV.getReflectedDecl(); if (auto *FD = dyn_cast(D); FD && FD->getTemplateSpecializationArgs()) break; else if (isa(D)) break; else if (auto *PVD = dyn_cast(D)) { std::string Name; (void) getParameterName(PVD, Name); HasIdentifier = !Name.empty(); } else if (auto *ND = dyn_cast(D)) HasIdentifier = (ND->getIdentifier() != nullptr); break; } case ReflectionKind::Template: { const TemplateDecl *TD = RV.getReflectedTemplate().getAsTemplateDecl(); if (auto *FTD = dyn_cast(TD)) if (isa(FTD->getTemplatedDecl())) break; HasIdentifier = (TD->getIdentifier() != nullptr); break; } case ReflectionKind::Namespace: { if (auto *ND = dyn_cast(RV.getReflectedNamespace())) HasIdentifier = (ND->getIdentifier() != nullptr); break; } case ReflectionKind::DataMemberSpec: { TagDataMemberSpec *TDMS = RV.getReflectedDataMemberSpec(); HasIdentifier = TDMS->Name && !TDMS->Name->empty(); break; } case ReflectionKind::Null: case ReflectionKind::BaseSpecifier: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Annotation: break; case ReflectionKind::EntityProxy: llvm_unreachable("proxies should already have been unwrapped"); } return SetAndSucceed(Result, makeBool(C, HasIdentifier)); } bool operator_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.getSizeType()); static constexpr OverloadedOperatorKind OperatorIndices[] = { OO_None, OO_New, OO_Delete, OO_Array_New, OO_Array_Delete, OO_Coawait, OO_Call, OO_Subscript, OO_Arrow, OO_ArrowStar, OO_Tilde, OO_Exclaim, OO_Plus, OO_Minus, OO_Star, OO_Slash, OO_Percent, OO_Caret, OO_Amp, OO_Pipe, OO_Equal, OO_PlusEqual, OO_MinusEqual, OO_StarEqual, OO_SlashEqual, OO_PercentEqual, OO_CaretEqual, OO_AmpEqual, OO_PipeEqual, OO_EqualEqual, OO_ExclaimEqual, OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual, OO_Spaceship, OO_AmpAmp, OO_PipePipe, OO_LessLess, OO_GreaterGreater, OO_LessLessEqual, OO_GreaterGreaterEqual, OO_PlusPlus, OO_MinusMinus, OO_Comma, }; auto findOperatorOf = [](FunctionDecl *FD) -> size_t { OverloadedOperatorKind OO = FD->getOverloadedOperator(); if (OO == OO_None) return 0; auto *OpPtr = std::find(std::begin(OperatorIndices), std::end(OperatorIndices), OO); assert(OpPtr < std::end(OperatorIndices)); return (OpPtr - OperatorIndices); }; APValue RV; if (!Evaluator(RV, Args[0], true)) return true; RV = MaybeUnproxy(C, RV); size_t OperatorId = 0; if (RV.isReflectedTemplate()) { const TemplateDecl *TD = RV.getReflectedTemplate().getAsTemplateDecl(); if (auto *FTD = dyn_cast(TD)) OperatorId = findOperatorOf(FTD->getTemplatedDecl()); } else if (RV.isReflectedDecl()) { if (auto *FD = dyn_cast(RV.getReflectedDecl())) OperatorId = findOperatorOf(FD); } if (OperatorId == 0) return Diagnoser(Range.getBegin(), diag::metafn_not_an_operator) << DescriptionOf(RV) << Range; return SetAndSucceed(Result, APValue(C.MakeIntValue(OperatorId, C.getSizeType()))); } bool source_location_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Type: return findTypeDeclLoc(Result, C, Evaluator, ResultTy, RV.getReflectedType()); case ReflectionKind::Declaration: return findDeclLoc(Result, C, Evaluator, ResultTy, RV.getReflectedDecl()); case ReflectionKind::Template: { TemplateName TName = RV.getReflectedTemplate(); return findDeclLoc(Result, C, Evaluator, ResultTy, TName.getAsTemplateDecl()); } case ReflectionKind::Namespace: return findDeclLoc(Result, C, Evaluator, ResultTy, RV.getReflectedNamespace()); case ReflectionKind::EntityProxy: return findDeclLoc(Result, C, Evaluator, ResultTy, RV.getReflectedEntityProxy()); case ReflectionKind::Parameter: return findDeclLoc(Result, C, Evaluator, ResultTy, RV.getReflectedParameter()); case ReflectionKind::BaseSpecifier: return findBaseSpecLoc(Result, C, Evaluator, ResultTy, RV.getReflectedBaseSpecifier()); case ReflectionKind::Annotation: return findAnnotLoc(Result, C, Evaluator, ResultTy, RV.getReflectedAnnotation()); case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Null: case ReflectionKind::DataMemberSpec: return findDeclLoc(Result, C, Evaluator, ResultTy, nullptr); } llvm_unreachable("unknown reflection kind"); } bool type_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: return Diagnoser(Range.getBegin(), diag::metafn_no_associated_property) << DescriptionOf(RV) << 0 << Range; case ReflectionKind::Object: case ReflectionKind::Value: { QualType QT = desugarType(RV.getTypeOfReflectedResult(C), /*UnwrapAliases=*/true, /*DropCV=*/false, /*DropRefs=*/false); return SetAndSucceed(Result, makeReflection(QT)); } case ReflectionKind::Declaration: { ValueDecl *VD = cast(RV.getReflectedDecl()); if (isa(VD)) return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 0 << DescriptionOf(RV) << Range; if (auto *FD = dyn_cast(VD)) Meta.EnsureInstantiationOfExceptionSpec(Range.getBegin(), FD); QualType QT = desugarType(VD->getType(), /*UnwrapAliases=*/ true, /*DropCV=*/false, /*DropRefs=*/false); return SetAndSucceed(Result, makeReflection(QT)); } case ReflectionKind::Parameter: { ParmVarDecl *PVD = RV.getReflectedParameter(); QualType QT = desugarType(PVD->getType(), /*UnwrapAliases=*/ true, /*DropCV=*/true, /*DropRefs=*/false); return SetAndSucceed(Result, makeReflection(QT)); } case ReflectionKind::BaseSpecifier: { QualType QT = RV.getReflectedBaseSpecifier()->getType(); QT = desugarType(QT, /*UnwrapAliases=*/true, /*DropCV=*/false, /*DropRefs=*/false); return SetAndSucceed(Result, makeReflection(QT)); } case ReflectionKind::DataMemberSpec: { QualType QT = RV.getReflectedDataMemberSpec()->Ty; QT = desugarType(QT, /*UnwrapAliases=*/true, /*DropCV=*/false, /*DropRefs=*/false); return SetAndSucceed(Result, makeReflection(QT)); } case ReflectionKind::Annotation: { QualType QT = RV.getReflectedAnnotation()->getArg()->getType(); QT = desugarType(QT, /*UnwrapAliases=*/true, /*DropCV=*/true, /*DropRefs=*/false); return SetAndSucceed(Result, makeReflection(QT)); } } llvm_unreachable("unknown reflection kind"); } bool parent_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; auto DiagWrapper = [&](unsigned DiagId) { if (DiagId && Diagnoser) return bool(Diagnoser(Range.getBegin(), DiagId) << DescriptionOf(RV) << Range); return DiagId > 0; }; switch (RV.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: if (Diagnoser) return Diagnoser(Range.getBegin(), diag::metafn_no_associated_property) << DescriptionOf(RV) << 1 << Range; return true; case ReflectionKind::Type: { if (TemplateName TName = findTemplateOfType(RV.getReflectedType()); !TName.isNull()) return DiagWrapper(parentOf(Result, TName.getAsTemplateDecl())); return DiagWrapper(parentOf(Result, findTypeDecl(RV.getReflectedType()))); } case ReflectionKind::Declaration: { if (TemplateName TName = findTemplateOfDecl(RV.getReflectedDecl()); !TName.isNull()) return DiagWrapper(parentOf(Result, TName.getAsTemplateDecl())); return DiagWrapper(parentOf(Result, RV.getReflectedDecl())); } case ReflectionKind::Template: { return DiagWrapper(parentOf(Result, RV.getReflectedTemplate().getAsTemplateDecl())); } case ReflectionKind::Parameter: { return DiagWrapper(parentOf(Result, RV.getReflectedParameter())); } case ReflectionKind::Namespace: if (isa(RV.getReflectedNamespace())) { if (Diagnoser) return Diagnoser(Range.getBegin(), diag::metafn_no_associated_property) << DescriptionOf(RV) << 1 << Range; return true; } return DiagWrapper(parentOf(Result, RV.getReflectedNamespace())); case ReflectionKind::EntityProxy: return DiagWrapper(parentOf(Result, RV.getReflectedEntityProxy())); case ReflectionKind::BaseSpecifier: { CXXRecordDecl *RD = RV.getReflectedBaseSpecifier()->getDerived(); QualType QT = desugarType(QualType(RD->getTypeForDecl(), 0), /*UnwrapAliases=*/true, /*DropCV=*/false, /*DropRefs=*/false); return SetAndSucceed(Result, makeReflection(QT)); } } llvm_unreachable("unknown reflection kind"); } bool underlying_entity_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Declaration: case ReflectionKind::Template: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return SetAndSucceed(Result, RV); case ReflectionKind::Type: { QualType QT = RV.getReflectedType(); QT = desugarType(QT, /*UnwrapAliases=*/true, /*DropCV=*/false, /*DropRefs=*/false); return SetAndSucceed(Result, makeReflection(QT)); } case ReflectionKind::Namespace: { Decl *NS = RV.getReflectedNamespace(); if (auto *A = dyn_cast(NS)) NS = A->getNamespace(); return SetAndSucceed(Result, makeReflection(NS)); } case ReflectionKind::EntityProxy: return SetAndSucceed(Result, MaybeUnproxy(C, RV)); } llvm_unreachable("unknown reflection kind"); } bool proxied_entity_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser,bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Declaration: case ReflectionKind::Namespace: case ReflectionKind::Template: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return DiagnoseReflectionKind(Diagnoser, Range, "an entity proxy"); case ReflectionKind::EntityProxy: return SetAndSucceed(Result, MaybeUnproxy(C, RV, false)); } llvm_unreachable("unknown reflection kind"); } bool object_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Object: return SetAndSucceed(Result, RV); case ReflectionKind::Declaration: { VarDecl *VD = dyn_cast(RV.getReflectedDecl()); if (!VD) return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 1 << DescriptionOf(RV) << Range; Meta.EnsureInstantiated(VD, Args[0]->getSourceRange()); QualType QT = VD->getType(); if (auto *LVRT = dyn_cast(QT)) { QT = LVRT->getPointeeType(); } Expr *Synthesized = DeclRefExpr::Create(C, NestedNameSpecifierLoc(), SourceLocation(), VD, false, Range.getBegin(), QT, VK_LValue, VD, nullptr); APValue Value; if (!Evaluator(Value, Synthesized, false) || !Value.isLValue()) return true; APValue OV = Value.Lift(QualType{}); return SetAndSucceed(Result, OV); } case ReflectionKind::Null: case ReflectionKind::Value: case ReflectionKind::Type: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::Parameter: case ReflectionKind::Template: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 1 << DescriptionOf(RV) << Range; } llvm_unreachable("unknown reflection kind"); } bool constant_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Value: return SetAndSucceed(Result, RV); case ReflectionKind::Object: { if (!RV.getTypeOfReflectedResult(C)->isStructuralType()) return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 2 << "an object of non-structural type" << Range; QualType ObjectTy = RV.getTypeOfReflectedResult(C); Expr *OVE = new (C) OpaqueValueExpr(Range.getBegin(), ObjectTy, VK_LValue); Expr *CE = ConstantExpr::Create(C, OVE, RV.getReflectedObject()); Expr::EvalResult ER; if (!CE->EvaluateAsRValue(ER, C, true)) return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 2 << "an object not usable in constant expressions" << Range; APValue Constant = ER.Val; QualType ConstantTy = ComputeResultType(RV.getTypeOfReflectedResult(C), Constant); if (ConstantTy->isRecordType()) { auto *TPO = C.getTemplateParamObjectDecl(ConstantTy, Constant); Constant = APValue(APValue::LValueBase{TPO}, CharUnits::Zero(), {}, false, false); ConstantTy = QualType{}; } return SetAndSucceed(Result, Constant.Lift(ConstantTy)); } case ReflectionKind::Declaration: { ValueDecl *Decl = RV.getReflectedDecl(); APValue Constant; QualType QT; if (auto *VD = dyn_cast(Decl)) { if (!VD->isUsableInConstantExpressions(C)) return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 2 << "a variable not usable in constant expressions" << Range; QT = VD->getType(); if (auto *LVRT = dyn_cast(QT)) QT = LVRT->getPointeeType(); Expr *Synthesized = DeclRefExpr::Create(C, NestedNameSpecifierLoc(), SourceLocation(), VD, false, Range.getBegin(), QT, VK_LValue, Decl, nullptr); if (!Evaluator(Constant, Synthesized, true)) llvm_unreachable("failed to evaluate variable usable in constant " "expressions"); } else if (isa(Decl)) { Expr *Synthesized = DeclRefExpr::Create(C, NestedNameSpecifierLoc(), SourceLocation(), Decl, false, Range.getBegin(), Decl->getType(), VK_PRValue, Decl, nullptr); QT = Synthesized->getType(); Expr::EvalResult ER; if (!Synthesized->EvaluateAsConstantExpr(ER, C)) llvm_unreachable("failed to evaluate enumerator constant"); Constant = ER.Val; } else if (auto *TPOD = dyn_cast(Decl)) { Constant = TPOD->getValue(); QT = TPOD->getType(); } else { return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 2 << DescriptionOf(RV) << Range; } QualType ConstantTy = ComputeResultType(QT, Constant); if (ConstantTy->isRecordType()) { auto *TPO = C.getTemplateParamObjectDecl(ConstantTy, Constant); Constant = APValue(APValue::LValueBase{TPO}, CharUnits::Zero(), {}, false, false); ConstantTy = QualType{}; } return SetAndSucceed(Result, Constant.Lift(ConstantTy)); } case ReflectionKind::Annotation: { CXX26AnnotationAttr *A = RV.getReflectedAnnotation(); APValue Constant = RV.getReflectedAnnotation()->getValue(); QualType ConstantTy = desugarType(A->getArg()->getType(), /*UnwrapAliases=*/true, /*DropCV=*/true, /*DropRefs=*/false); if (ConstantTy->isRecordType()) { auto *TPO = C.getTemplateParamObjectDecl(ConstantTy, Constant); Constant = APValue(APValue::LValueBase{TPO}, CharUnits::Zero(), {}, false, false); ConstantTy = QualType{}; } return SetAndSucceed(Result, Constant.Lift(ConstantTy)); } case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::Parameter: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 2 << DescriptionOf(RV) << Range; } llvm_unreachable("unknown reflection kind"); } bool template_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { TemplateName TName = findTemplateOfType(RV.getReflectedType()); if (TName.isNull()) return DiagnoseReflectionKind(Diagnoser, Range, "a template specialization"); return SetAndSucceed(Result, makeReflection(TName)); } case ReflectionKind::Declaration: { TemplateName TName = findTemplateOfDecl(RV.getReflectedDecl()); if (TName.isNull()) return DiagnoseReflectionKind(Diagnoser, Range, "a template specialization"); return SetAndSucceed(Result, makeReflection(TName)); } case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::Parameter: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return DiagnoseReflectionKind(Diagnoser, Range, "a template specialization", DescriptionOf(RV)); return true; } llvm_unreachable("unknown reflection kind"); } static bool CanActAsTemplateArg(const APValue &RV) { switch (RV.getReflectionKind()) { case ReflectionKind::Type: case ReflectionKind::Object: case ReflectionKind::Value: return true; case ReflectionKind::Declaration: return (!isa(RV.getReflectedDecl())); case ReflectionKind::Template: { TemplateDecl *TDecl = RV.getReflectedTemplate().getAsTemplateDecl(); return isa(TDecl); } case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: case ReflectionKind::Null: return false; case ReflectionKind::EntityProxy: llvm_unreachable("expected proxies to have been unwrapped before calling"); } llvm_unreachable("unknown reflection kind"); } static TemplateArgument TArgFromReflection(ASTContext &C, MetaActions &Meta, EvalFn Evaluator, const APValue &RV, SourceLocation Loc) { switch (RV.getReflectionKind()) { case ReflectionKind::Type: return RV.getReflectedType().getCanonicalType(); case ReflectionKind::Object: { QualType RefTy = C.getLValueReferenceType(RV.getTypeOfReflectedResult(C)); return TemplateArgument(C, RefTy, RV.getReflectedObject(), false); } case ReflectionKind::Value: { APValue Lowered = RV.getReflectedValue(); QualType ResultTy = RV.getTypeOfReflectedResult(C); if (Lowered.isInt()) { return TemplateArgument(C, Lowered.getInt(), ResultTy.getCanonicalType()); } TemplateArgument TArg(C, ResultTy, Lowered, false); return TArg; } case ReflectionKind::Declaration: { ValueDecl *Decl = RV.getReflectedDecl(); if (Decl->isInvalidDecl()) break; if (!Meta.EnsureInstantiated(Decl, SourceRange(Loc, Loc))) return TemplateArgument(); QualType QT = desugarType(Decl->getType(), /*UnwrapAliases=*/ false, /*DropCV=*/false, /*DropRefs=*/true); // Don't worry about the cost of creating an expression here: The template // substitution machinery will otherwise create one from the argument // anyway, so we aren't really losing any efficiency here. Expr *Synthesized = DeclRefExpr::Create(C, NestedNameSpecifierLoc(), SourceLocation(), Decl, false, Loc, QT, VK_LValue, Decl, nullptr); return TemplateArgument(Synthesized, true); } case ReflectionKind::Template: return TemplateArgument(RV.getReflectedTemplate()); break; case ReflectionKind::EntityProxy: llvm_unreachable("expected proxies to have been unwrapped before calling"); default: llvm_unreachable("unimplemented for template argument kind"); } return TemplateArgument(); } bool substitute(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert( Args[1]->getType()->getPointeeOrArrayElementType()->isReflectionType()); assert(Args[2]->getType()->isIntegerType()); APValue Template; if (!Evaluator(Template, Args[0], true)) return true; if (!Template.isReflectedTemplate()) return DiagnoseReflectionKind(Diagnoser, Range, "a template", DescriptionOf(Template)); TemplateDecl *TDecl = Template.getReflectedTemplate().getAsTemplateDecl(); if (TDecl->isInvalidDecl()) return true; APValue DiagnoseAPV; if (!Evaluator(DiagnoseAPV, Args[3], true)) return true; bool NoDiagnose = !DiagnoseAPV.getInt().getBoolValue(); auto ElideDiagnosis = [&] { return SetAndSucceed(Result, makeReflection(nullptr)); }; SmallVector TArgs; { // Evaluate how many template arguments were provided. APValue NumArgs; if (!Evaluator(NumArgs, Args[2], true)) return true; size_t nArgs = NumArgs.getInt().getExtValue(); TArgs.reserve(nArgs); for (uint64_t k = 0; k < nArgs; ++k) { llvm::APInt Idx(C.getTypeSize(C.getSizeType()), k, false); Expr *Synthesized = IntegerLiteral::Create(C, Idx, C.getSizeType(), Args[1]->getExprLoc()); Synthesized = new (C) ArraySubscriptExpr(Args[1], Synthesized, C.MetaInfoTy, VK_LValue, OK_Ordinary, Range.getBegin()); if (Synthesized->isValueDependent() || Synthesized->isTypeDependent()) return true; APValue Unwrapped; if (!Evaluator(Unwrapped, Synthesized, true) || !Unwrapped.isReflection()) return true; Unwrapped = MaybeUnproxy(C, Unwrapped); if (!CanActAsTemplateArg(Unwrapped)) return NoDiagnose ? ElideDiagnosis() : Diagnoser(Range.getBegin(), diag::metafn_cannot_be_arg) << DescriptionOf(Unwrapped) << 1 << Range; TemplateArgument TArg = TArgFromReflection(C, Meta, Evaluator, Unwrapped, Range.getBegin()); if (TArg.isNull()) return true; TArgs.push_back(TArg); } } SmallVector ExpandedTArgs; expandTemplateArgPacks(TArgs, ExpandedTArgs); // Lookup cached specialization; if found, return it. llvm::FoldingSetNodeID ID; { ID.AddPointer(TDecl); for (const TemplateArgument &TArg : ExpandedTArgs) TArg.Profile(ID, C); } unsigned SubstitutionHash = ID.ComputeHash(); if (C.checkCachedSubstitution(SubstitutionHash, &Result)) return false; if (!Meta.CheckTemplateArgumentList(TDecl, ExpandedTArgs, NoDiagnose, Args[0]->getExprLoc())) return NoDiagnose ? ElideDiagnosis() : true; for (const auto &TArg : ExpandedTArgs) if (TArg.getKind() == TemplateArgument::Expression && TArg.getAsExpr()->containsErrors()) return true; if (auto *CTD = dyn_cast(TDecl)) { void *InsertPos; ClassTemplateSpecializationDecl *TSpecDecl = CTD->findSpecialization(ExpandedTArgs, InsertPos); if (!TSpecDecl) { TSpecDecl = ClassTemplateSpecializationDecl::Create( C, CTD->getTemplatedDecl()->getTagKind(), CTD->getDeclContext(), Range.getBegin(), Range.getBegin(), CTD, ExpandedTArgs, false, nullptr); CTD->AddSpecialization(TSpecDecl, InsertPos); } assert(TSpecDecl); APValue RV(ReflectionKind::Type, const_cast(TSpecDecl->getTypeForDecl())); //C.recordCachedSubstitution(SubstitutionHash, RV); return SetAndSucceed(Result, RV); } if (auto *TATD = dyn_cast(TDecl)) { TArgs.clear(); expandTemplateArgPacks(ExpandedTArgs, TArgs); QualType QT = Meta.Substitute(TATD, TArgs, Range.getBegin()); if(QT.isNull()) { // substitution failed after validating arguments return true; } APValue RV = makeReflection(QT); //C.recordCachedSubstitution(SubstitutionHash, RV); return SetAndSucceed(Result, makeReflection(QT)); } if (auto *FTD = dyn_cast(TDecl)) { FunctionDecl *Spec = Meta.Substitute(FTD, ExpandedTArgs, Range.getBegin()); assert(Spec && "substitution failed after validating arguments?"); if (Spec->getReturnType()->isUndeducedType()) return NoDiagnose ? ElideDiagnosis() : Diagnoser(Range.getBegin(), diag::metafn_undeduced_placeholder) << Spec << Spec->getType() << Range; APValue RV = makeReflection(Spec); //C.recordCachedSubstitution(SubstitutionHash, RV); return SetAndSucceed(Result, RV); } if (auto *VTD = dyn_cast(TDecl)) { TArgs.clear(); expandTemplateArgPacks(ExpandedTArgs, TArgs); VarDecl *Spec = Meta.Substitute(VTD, TArgs, Range.getBegin()); assert(Spec && "substitution failed after validating arguments?"); APValue RV = makeReflection(Spec); //C.recordCachedSubstitution(SubstitutionHash, RV); return SetAndSucceed(Result, makeReflection(Spec)); } if (auto *CD = dyn_cast(TDecl)) { TArgs.clear(); expandTemplateArgPacks(ExpandedTArgs, TArgs); Expr *Spec = Meta.Substitute(CD, TArgs, Range.getBegin()); assert(Spec && "substitution failed after validating arguments?"); APValue SatisfiesConcept; if (!Evaluator(SatisfiesConcept, Spec, true)) llvm_unreachable("failed to evaluate substituted concept"); APValue RV = SatisfiesConcept.Lift(C.BoolTy); //C.recordCachedSubstitution(SubstitutionHash, RV); return SetAndSucceed(Result, SatisfiesConcept.Lift(C.BoolTy)); } llvm_unreachable("unimplemented for template kind"); } bool extract(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(Args[1]->getType()->isReflectionType()); bool ReturnsLValue = false; QualType RawResultTy = ResultTy; if (auto *LVRT = dyn_cast(ResultTy)) { ReturnsLValue = true; ResultTy = LVRT->getPointeeType(); } auto extractLambda = [&](APValue &Out, CXXRecordDecl *RD) -> bool { if (!RD->isCapturelessLambda()) return true; CXXMethodDecl *CallOp = RD->getLambdaStaticInvoker(); QualType LambdaPtrTy = C.getPointerType(CallOp->getType()); if (LambdaPtrTy.getCanonicalType().getTypePtr() != ResultTy.getCanonicalType().getTypePtr()) return Diagnoser(Range.getBegin(), diag::metafn_extract_type_mismatch) << 0 << QualType(RD->getTypeForDecl(), 0) << 0 << ResultTy << Range; // If not already done, generate a fake body for the call-operator. // The real body is generated during CodeGen. if (!CallOp->hasBody()) { CallOp->markUsed(C); CallOp->setReferenced(); CallOp->setBody(new (C) CompoundStmt(Range.getBegin())); } APValue CallOpLV(CallOp, CharUnits::Zero(), {}, false, false); return SetAndSucceed(Out, CallOpLV); }; APValue RV; if (!Evaluator(RV, Args[1], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Object: { QualType ObjectTy = RV.getTypeOfReflectedResult(C); if (auto *RD = ObjectTy->getAsCXXRecordDecl(); RD && RD->isLambda() && ResultTy->isPointerType()) return extractLambda(Result, RD); if (ObjectTy.getCanonicalType().getTypePtr() != ResultTy.getCanonicalType().getTypePtr()) return Diagnoser(Range.getBegin(), diag::metafn_extract_type_mismatch) << 1 << ObjectTy << ReturnsLValue << ResultTy << Range; Expr *OVE = new (C) OpaqueValueExpr(Range.getBegin(), ObjectTy, VK_LValue); Expr *CE = ConstantExpr::Create(C, OVE, RV.getReflectedObject()); if (!Evaluator(RV, CE, !ReturnsLValue)) return true; return SetAndSucceed(Result, RV); } case ReflectionKind::Value: { QualType ValueTy = RV.getTypeOfReflectedResult(C); if (ReturnsLValue) return Diagnoser(Range.getBegin(), diag::metafn_cannot_extract) << 1 << DescriptionOf(RV) << Range; if (ValueTy.getCanonicalType().getTypePtr() != ResultTy.getCanonicalType().getTypePtr()) return Diagnoser(Range.getBegin(), diag::metafn_extract_type_mismatch) << 0 << ValueTy << ReturnsLValue << ResultTy << Range; return SetAndSucceed(Result, RV.getReflectedValue()); } case ReflectionKind::Annotation: { if (ReturnsLValue) return Diagnoser(Range.getBegin(), diag::metafn_cannot_extract) << 1 << DescriptionOf(RV) << Range; CXX26AnnotationAttr *A = RV.getReflectedAnnotation(); if (auto *RD = A->getArg()->getType()->getAsCXXRecordDecl(); RD && RD->isLambda() && ResultTy->isPointerType()) return extractLambda(Result, RD); if (A->getArg()->getType().getCanonicalType().getTypePtr() != ResultTy.getCanonicalType().getTypePtr()) return Diagnoser(Range.getBegin(), diag::metafn_extract_type_mismatch) << 3 << A->getArg()->getType() << ReturnsLValue << ResultTy << Range; return SetAndSucceed(Result, A->getValue()); } case ReflectionKind::Declaration: { ValueDecl *Decl = RV.getReflectedDecl(); Meta.EnsureInstantiated(Decl, Args[1]->getSourceRange()); if (auto *RD = Decl->getType()->getAsCXXRecordDecl(); RD && RD->isLambda() && ResultTy->isPointerType()) return extractLambda(Result, RD); if (isa(Decl)) { Expr *Synthesized; if (isa(Decl->getType().getCanonicalType())) { // We have a reflection of an object with reference type. // Synthesize a 'DeclRefExpr' designating the object, such that constant // evaluation resolves the underlying referenced entity. ReturnsLValue = true; if (RawResultTy.getCanonicalType().getTypePtr() != Decl->getType().getCanonicalType().getTypePtr()) return Diagnoser(Range.getBegin(), diag::metafn_extract_type_mismatch) << 1 << Decl->getType() << 1 << ResultTy << Range; NestedNameSpecifierLocBuilder NNSLocBuilder; if (auto *ParentClsDecl = dyn_cast_or_null( Decl->getDeclContext())) { TypeSourceInfo *TSI = C.CreateTypeSourceInfo( QualType(ParentClsDecl->getTypeForDecl(), 0), 0); NNSLocBuilder.Extend(C, TSI->getTypeLoc(), Range.getBegin()); } Synthesized = DeclRefExpr::Create(C, NNSLocBuilder.getTemporary(), SourceLocation(), Decl, false, Range.getBegin(), ResultTy, VK_LValue, Decl, nullptr); } else if (auto *ArrTy = dyn_cast(Decl->getType())) { QualType Elt = ArrTy->getElementType(); if (auto *VD = dyn_cast(Decl)) { if (VD->isConstexpr()) { Elt.addConst(); } } ReturnsLValue = true; if (!RawResultTy->isPointerType() || !RawResultTy->getPointeeType().isAtLeastAsQualifiedAs(Elt, C)) return Diagnoser(Range.getBegin(), diag::metafn_extract_type_mismatch) << 1 << C.getPointerType(Elt) << 1 << ResultTy << Range; NestedNameSpecifierLocBuilder NNSLocBuilder; if (auto *ParentClsDecl = dyn_cast_or_null( Decl->getDeclContext())) { TypeSourceInfo *TSI = C.CreateTypeSourceInfo( QualType(ParentClsDecl->getTypeForDecl(), 0), 0); NNSLocBuilder.Extend(C, TSI->getTypeLoc(), Range.getBegin()); } APValue::LValuePathEntry Path[1] = {APValue::LValuePathEntry::ArrayIndex(0)}; return SetAndSucceed(Result, APValue(Decl, CharUnits::Zero(), Path, false)); } else { // We have a reflection of a (possibly local) non-reference variable. // Synthesize an lvalue by reaching up the call stack. if (ResultTy.getCanonicalType().getTypePtr() != Decl->getType().getCanonicalType().getTypePtr()) return Diagnoser(Range.getBegin(), diag::metafn_extract_type_mismatch) << 0 << Decl->getType() << ReturnsLValue << ResultTy << Range; Synthesized = ExtractLValueExpr::Create(C, Range, ResultTy, Decl); } if (Synthesized->getType().getCanonicalType().getTypePtr() != ResultTy.getCanonicalType().getTypePtr()) return Diagnoser(Range.getBegin(), diag::metafn_extract_type_mismatch) << 0 << Decl->getType() << ReturnsLValue << ResultTy << Range; return !Evaluator(Result, Synthesized, !ReturnsLValue); } else if (isa(Decl)) { return Diagnoser(Range.getBegin(), diag::metafn_extract_structured_binding) << Range; } else if (ReturnsLValue) { // Only variables may be returned as LValues. return Diagnoser(Range.getBegin(), diag::metafn_cannot_extract) << 1 << DescriptionOf(RV); } else if (isa(Decl)) { // Extracting a non-static member as a pointer. if (auto *FD = dyn_cast(Decl); FD && FD->isBitField()) return Diagnoser(Range.getBegin(), diag::metafn_cannot_extract) << 2 << DescriptionOf(RV) << Range; DeclContext *ObjDC = Decl->getDeclContext(); while (ObjDC && [](DeclContext *DC) { if (auto *RD = dyn_cast(DC)) return RD->isAnonymousStructOrUnion(); else return DC->isTransparentContext(); }(ObjDC)) if (isa(ObjDC)) // Can happen if Target was a member of a static anonymous union at // namespace scope. return Diagnoser(Range.getBegin(), diag::metafn_cannot_extract) << 2 << "a field that is not a member of a class"; else ObjDC = ObjDC->getParent(); QualType MemPtrTy = C.getMemberPointerType(Decl->getType(), nullptr, cast(ObjDC)); if (MemPtrTy.getCanonicalType().getTypePtr() != ResultTy.getCanonicalType().getTypePtr()) return Diagnoser(Range.getBegin(), diag::metafn_extract_entity_type_mismatch) << ResultTy << DescriptionOf(RV) << MemPtrTy << Range; APValue MemPtrLV(Decl, false, ArrayRef {}); return SetAndSucceed(Result, MemPtrLV); } else if (auto *ECD = dyn_cast(Decl)) { if (ECD->getType().getCanonicalType().getTypePtr() != ResultTy.getCanonicalType().getTypePtr()) return Diagnoser(Range.getBegin(), diag::metafn_extract_type_mismatch) << 2 << Decl->getType() << 0 << ResultTy << Range; return SetAndSucceed(Result, APValue(ECD->getInitVal())); } else { QualType FnPtrTy = C.getPointerType(Decl->getType()); if (FnPtrTy.getCanonicalType().getTypePtr() != ResultTy.getCanonicalType().getTypePtr()) return Diagnoser(Range.getBegin(), diag::metafn_extract_type_mismatch) << 0 << Decl->getType() << ReturnsLValue << ResultTy << Range; return SetAndSucceed(Result, APValue(Decl, CharUnits::Zero(), {}, false, false)); } } case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::Parameter: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: return Diagnoser(Range.getBegin(), diag::metafn_cannot_extract) << (ReturnsLValue ? 1 : 0) << DescriptionOf(RV) << Range; } llvm_unreachable("invalid reflection type"); } template bool is_ACCESS(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { bool HasTargetAccess = false; if (const Decl *D = findTypeDecl(RV.getReflectedType())) HasTargetAccess = (D->getAccess() == Specifier); return SetAndSucceed(Result, makeBool(C, HasTargetAccess)); } case ReflectionKind::Declaration: { bool HasTargetAccess = (RV.getReflectedDecl()->getAccess() == Specifier); return SetAndSucceed(Result, makeBool(C, HasTargetAccess)); } case ReflectionKind::EntityProxy: { bool HasTargetAccess = (RV.getReflectedEntityProxy()->getAccess() == Specifier); return SetAndSucceed(Result, makeBool(C, HasTargetAccess)); } case ReflectionKind::Template: { const Decl *D = RV.getReflectedTemplate().getAsTemplateDecl(); bool HasTargetAccess = (D->getAccess() == Specifier); return SetAndSucceed(Result, makeBool(C, HasTargetAccess)); } case ReflectionKind::BaseSpecifier: { CXXBaseSpecifier *Base = RV.getReflectedBaseSpecifier(); bool HasTargetAccess = (Base->getAccessSpecifier() == Specifier); return SetAndSucceed(Result, makeBool(C, HasTargetAccess)); } case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::DataMemberSpec: case ReflectionKind::Parameter: case ReflectionKind::Annotation: case ReflectionKind::Namespace: return SetAndSucceed(Result, makeBool(C, false)); } llvm_unreachable("invalid reflection type"); } template static inline bool is_ClassMember_ACCESS(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { [[maybe_unused]] bool scratch = is_class_member(Result, C, Meta, Evaluator, Diagnoser, AllowInjection, ResultTy, Range, Args, ContainingDecl); if (const bool isClassMember = Result.getInt().getBoolValue();isClassMember) { return is_ACCESS(Result, C, Meta, Evaluator, Diagnoser, AllowInjection, ResultTy, Range, Args, ContainingDecl); } // fallthrough: base-class relationship scratch = is_base(Result, C, Meta, Evaluator, Diagnoser, AllowInjection, ResultTy, Range, Args, ContainingDecl); if (const bool isBaseClass = Result.getInt().getBoolValue();isBaseClass) { return is_ACCESS(Result, C, Meta, Evaluator, Diagnoser, AllowInjection, ResultTy, Range, Args, ContainingDecl); } return false; } bool is_public(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { return is_ClassMember_ACCESS( Result, C, Meta, Evaluator, Diagnoser, AllowInjection, ResultTy, Range, Args, ContainingDecl); } bool is_protected(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { return is_ClassMember_ACCESS( Result, C, Meta, Evaluator, Diagnoser, AllowInjection, ResultTy, Range, Args, ContainingDecl); } bool is_private(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { return is_ClassMember_ACCESS( Result, C, Meta, Evaluator, Diagnoser, AllowInjection, ResultTy, Range, Args, ContainingDecl); } bool is_virtual(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsVirtual = false; switch (RV.getReflectionKind()) { case ReflectionKind::Declaration: { if (auto *MD = dyn_cast(RV.getReflectedDecl())) IsVirtual = MD->isVirtual(); return SetAndSucceed(Result, makeBool(C, IsVirtual)); } case ReflectionKind::BaseSpecifier: { IsVirtual = RV.getReflectedBaseSpecifier()->isVirtual(); return SetAndSucceed(Result, makeBool(C, IsVirtual)); } case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return SetAndSucceed(Result, makeBool(C, IsVirtual)); } llvm_unreachable("invalid reflection type"); } bool is_pure_virtual(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsPureVirtual = false; if (RV.isReflectedDecl()) if (const auto *FD = dyn_cast(RV.getReflectedDecl())) IsPureVirtual = FD->isPureVirtual(); return SetAndSucceed(Result, makeBool(C, IsPureVirtual)); } bool is_override(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsOverride = false; if (RV.isReflectedDecl()) if (auto *MD = dyn_cast(RV.getReflectedDecl())) IsOverride = MD->size_overridden_methods() > 0; return SetAndSucceed(Result, makeBool(C, IsOverride)); } bool is_deleted(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsDeleted = false; if (RV.isReflectedDecl()) if (auto *FD = dyn_cast(RV.getReflectedDecl())) IsDeleted = FD->isDeleted(); return SetAndSucceed(Result, makeBool(C, IsDeleted)); } bool is_defaulted(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsDefaulted = false; if (RV.isReflectedDecl()) if (auto *FD = dyn_cast(RV.getReflectedDecl())) IsDefaulted = FD->getMostRecentDecl()->isDefaulted(); return SetAndSucceed(Result, makeBool(C, IsDefaulted)); } bool is_explicit(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsExplicit = false; if (RV.isReflectedDecl()) { if (auto *CtorD = dyn_cast(RV.getReflectedDecl())) IsExplicit = CtorD->getExplicitSpecifier().isExplicit(); else if (auto *ConvD = dyn_cast(RV.getReflectedDecl())) IsExplicit = ConvD->getExplicitSpecifier().isExplicit(); } return SetAndSucceed(Result, makeBool(C, IsExplicit)); } bool is_noexcept(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsNoexcept = false; if (RV.isReflectedType()) IsNoexcept = isFunctionOrMethodNoexcept(RV.getReflectedType()); else if (RV.isReflectedDecl()) { if (auto *FD = dyn_cast(RV.getReflectedDecl())) Meta.EnsureInstantiationOfExceptionSpec(Range.getBegin(), FD); IsNoexcept = isFunctionOrMethodNoexcept(RV.getReflectedDecl()->getType()); } return SetAndSucceed(Result, makeBool(C, IsNoexcept)); } bool is_bit_field(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) { if (const auto *FD = dyn_cast(RV.getReflectedDecl())) result = FD->isBitField(); else if (const auto *BD = dyn_cast(RV.getReflectedDecl())) result = BD->getBinding()->refersToBitField(); } else if (RV.isReflectedDataMemberSpec()) { result = RV.getReflectedDataMemberSpec()->BitWidth.has_value(); } return SetAndSucceed(Result, makeBool(C, result)); } bool is_enumerator(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) result = isa(RV.getReflectedDecl()); return SetAndSucceed(Result, makeBool(C, result)); } bool is_const(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::Parameter: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Type: { bool result = isConstQualifiedType(RV.getReflectedType()); return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::Declaration: { bool result = isConstQualifiedType(RV.getReflectedDecl()->getType()); return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::Object: case ReflectionKind::Value: { bool result = isConstQualifiedType(RV.getTypeOfReflectedResult(C)); return SetAndSucceed(Result, makeBool(C, result)); } } llvm_unreachable("invalid reflection type"); } bool is_volatile(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::Parameter: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Type: { bool result = isVolatileQualifiedType(RV.getReflectedType()); return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::Declaration: { bool result = isVolatileQualifiedType(RV.getReflectedDecl()->getType()); return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::Object: case ReflectionKind::Value: { bool result = isVolatileQualifiedType(RV.getTypeOfReflectedResult(C)); return SetAndSucceed(Result, makeBool(C, result)); } } llvm_unreachable("invalid reflection type"); } bool is_mutable_member(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsMutableMember = false; if (RV.isReflectedDecl()) if (auto *FD = dyn_cast(RV.getReflectedDecl())) IsMutableMember = FD->isMutable(); return SetAndSucceed(Result, makeBool(C, IsMutableMember)); } bool is_lvalue_reference_qualified(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedType()) { if (auto FT = dyn_cast(RV.getReflectedType())) result = (FT->getRefQualifier() == RQ_LValue); } else if (RV.isReflectedDecl()) { if (const auto *FD = dyn_cast(RV.getReflectedDecl())) if (auto FT = dyn_cast(FD->getType())) result = (FT->getRefQualifier() == RQ_LValue); } return SetAndSucceed(Result, makeBool(C, result)); } bool is_rvalue_reference_qualified(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedType()) { if (auto FT = dyn_cast(RV.getReflectedType())) result = (FT->getRefQualifier() == RQ_RValue); } else if (RV.isReflectedDecl()) { if (const auto *FD = dyn_cast(RV.getReflectedDecl())) if (auto FT = dyn_cast(FD->getType())) result = (FT->getRefQualifier() == RQ_RValue); } return SetAndSucceed(Result, makeBool(C, result)); } bool has_static_storage_duration(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) { if (const auto *VD = dyn_cast(RV.getReflectedDecl())) result = VD->getStorageDuration() == SD_Static; else if (isa(RV.getReflectedDecl())) result = true; } else if (RV.isReflectedObject()) { result = true; } return SetAndSucceed(Result, makeBool(C, result)); } bool has_thread_storage_duration(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) if (const auto *VD = dyn_cast(RV.getReflectedDecl())) result = VD->getStorageDuration() == SD_Thread; return SetAndSucceed(Result, makeBool(C, result)); } bool has_automatic_storage_duration(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) if (const auto *VD = dyn_cast(RV.getReflectedDecl())) result = VD->getStorageDuration() == SD_Automatic; return SetAndSucceed(Result, makeBool(C, result)); } bool has_internal_linkage(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedType()) { if (NamedDecl *typeDecl = dyn_cast_or_null(findTypeDecl(RV.getReflectedType()))) result = (typeDecl->getFormalLinkage() == Linkage::Internal); } else if (RV.isReflectedDecl()) { if (const auto *ND = dyn_cast(RV.getReflectedDecl())) result = (ND->getFormalLinkage() == Linkage::Internal); } else if (RV.isReflectedObject()) { if (APValue::LValueBase LVBase = RV.getReflectedObject().getLValueBase(); LVBase.is()) { const ValueDecl *VD = LVBase.get(); result = (VD->getFormalLinkage() == Linkage::Internal); } } return SetAndSucceed(Result, makeBool(C, result)); } bool has_module_linkage(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedType()) { if (NamedDecl *typeDecl = dyn_cast_or_null(findTypeDecl(RV.getReflectedType()))) result = (typeDecl->getFormalLinkage() == Linkage::Module); } else if (RV.isReflectedDecl()) { if (const auto *ND = dyn_cast(RV.getReflectedDecl())) result = (ND->getFormalLinkage() == Linkage::Module); } else if (RV.isReflectedObject()) { if (APValue::LValueBase LVBase = RV.getReflectedObject().getLValueBase(); LVBase.is()) { const ValueDecl *VD = LVBase.get(); result = (VD->getFormalLinkage() == Linkage::Module); } } return SetAndSucceed(Result, makeBool(C, result)); } bool has_external_linkage(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedType()) { if (NamedDecl *typeDecl = dyn_cast_or_null(findTypeDecl(RV.getReflectedType()))) result = (typeDecl->getFormalLinkage() == Linkage::External || typeDecl->getFormalLinkage() == Linkage::UniqueExternal); } else if (RV.isReflectedDecl()) { if (const auto *ND = dyn_cast(RV.getReflectedDecl())) result = (ND->getFormalLinkage() == Linkage::External || ND->getFormalLinkage() == Linkage::UniqueExternal); } else if (RV.isReflectedObject()) { if (APValue::LValueBase LVBase = RV.getReflectedObject().getLValueBase(); LVBase.is()) { const ValueDecl *VD = LVBase.get(); result = (VD->getFormalLinkage() == Linkage::External || VD->getFormalLinkage() == Linkage::UniqueExternal); } } return SetAndSucceed(Result, makeBool(C, result)); } bool has_linkage(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedType()) { if (NamedDecl *typeDecl = dyn_cast_or_null(findTypeDecl(RV.getReflectedType()))) result = typeDecl->hasLinkage(); } else if (RV.isReflectedDecl()) { if (const auto *ND = dyn_cast(RV.getReflectedDecl())) result = ND->hasLinkage(); } else if (RV.isReflectedObject()) { if (APValue::LValueBase LVBase = RV.getReflectedObject().getLValueBase(); LVBase.is()) { const ValueDecl *VD = LVBase.get(); result = (VD->hasLinkage()); } } return SetAndSucceed(Result, makeBool(C, result)); } bool is_class_member(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue Scratch; bool result = false; decltype(Diagnoser) SwallowDiags {}; if (!parent_of(Scratch, C, Meta, Evaluator, SwallowDiags, AllowInjection, C.MetaInfoTy, Range, Args, ContainingDecl)) { assert(Scratch.isReflection()); // For unscoped enumerators, parent_of will return its enumeration type // We need now to lookup context on that type if (Scratch.isReflectedType() && Scratch.getReflectedType()->isUnscopedEnumerationType()) { Decl *D = findTypeDecl(Scratch.getReflectedType()); result = D && D->getDeclContext() && D->getDeclContext()->isRecord(); } else { result = Scratch.isReflectedType() && Scratch.getReflectedType()->isRecordType(); } } return SetAndSucceed(Result, makeBool(C, result)); } bool is_namespace_member(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue Scratch; bool result = false; decltype(Diagnoser) SwallowDiags {}; if (!parent_of(Scratch, C, Meta, Evaluator, SwallowDiags, AllowInjection, C.MetaInfoTy, Range, Args, ContainingDecl)) { assert(Scratch.isReflection()); result = Scratch.isReflectedNamespace(); } return SetAndSucceed(Result, makeBool(C, result)); } bool is_nonstatic_data_member(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) { if (auto *FD = dyn_cast(RV.getReflectedDecl())) { // Unnamed bit-fields are not members, but just about every other field // should be a nonstatic data member. result = (!FD->isBitField() || FD->getIdentifier()); } } return SetAndSucceed(Result, makeBool(C, result)); } bool is_static_member(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; switch (RV.getReflectionKind()) { case ReflectionKind::Declaration: { const ValueDecl *D = cast(RV.getReflectedDecl()); if (const auto *MD = dyn_cast(D)) result = MD->isStatic(); else if (const auto *VD = dyn_cast(D)) result = VD->isStaticDataMember(); return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::Template: { const Decl *D = RV.getReflectedTemplate().getAsTemplateDecl(); if (const auto *FTD = dyn_cast(D)) { if (const auto *MD = dyn_cast(FTD->getTemplatedDecl())) result = MD->isStatic(); } else if (const auto *VTD = dyn_cast(D)) { if (const auto *VD = dyn_cast(VTD->getTemplatedDecl())) result = VD->isStaticDataMember(); } return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return SetAndSucceed(Result, makeBool(C, result)); case ReflectionKind::EntityProxy: llvm_unreachable("proxies should already have been unwrapped"); } llvm_unreachable("unknown reflection kind"); } bool is_base(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; return SetAndSucceed(Result, makeBool(C, RV.isReflectedBaseSpecifier())); } bool is_data_member_spec(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; return SetAndSucceed(Result, makeBool(C, RV.isReflectedDataMemberSpec())); } bool is_namespace(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; return SetAndSucceed(Result, makeBool(C, RV.isReflectedNamespace())); } bool is_function(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) result = isa(RV.getReflectedDecl()); return SetAndSucceed(Result, makeBool(C, result)); } bool is_variable(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) result = isa(RV.getReflectedDecl()); return SetAndSucceed(Result, makeBool(C, result)); } bool is_type(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; return SetAndSucceed(Result, makeBool(C, RV.isReflectedType())); } bool is_alias(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { bool result = isTypeAlias(RV.getReflectedType()); return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::Namespace: { bool result = isa(RV.getReflectedNamespace()); return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::Template: { TemplateDecl *TDecl = RV.getReflectedTemplate().getAsTemplateDecl(); bool result = isa(TDecl); return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Declaration: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Parameter: case ReflectionKind::Annotation: case ReflectionKind::EntityProxy: return SetAndSucceed(Result, makeBool(C, false)); } llvm_unreachable("unknown reflection kind"); } bool is_entity_proxy(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; return SetAndSucceed(Result, makeBool(C, RV.isReflectedEntityProxy())); } bool is_complete_type(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedType()) { // If this is a declared type with a reachable definition, ensure that the // type is instantiated. if (Decl *typeDecl = findTypeDecl(RV.getReflectedType())) (void) Meta.EnsureInstantiated(typeDecl, Range); result = !RV.getReflectedType()->isIncompleteType(); } return SetAndSucceed(Result, makeBool(C, result)); } bool has_complete_definition(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; switch (RV.getReflectionKind()) { case ReflectionKind::Type: if (Decl *typeDecl = findTypeDecl(RV.getReflectedType())) { if (auto *TD = dyn_cast(typeDecl)) result = (TD->getDefinition() != nullptr && !TD->getDefinition()->isBeingDefined()); } break; case ReflectionKind::Declaration: { if (auto *FD = dyn_cast(RV.getReflectedDecl())) result = (FD->getDefinition() != nullptr && FD->getDefinition()->hasBody()); break; } case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: break; case ReflectionKind::EntityProxy: llvm_unreachable("proxies should already have been unwrapped"); } return SetAndSucceed(Result, makeBool(C, result)); } bool is_enumerable_type(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; switch (RV.getReflectionKind()) { case ReflectionKind::Type: if (Decl *typeDecl = findTypeDecl(RV.getReflectedType())) { if (auto *TD = dyn_cast(typeDecl)) { (void) Meta.EnsureInstantiated(TD, Range); result = (TD->getDefinition() != nullptr && !TD->getDefinition()->isBeingDefined()); } } break; case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Declaration: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: break; case ReflectionKind::EntityProxy: llvm_unreachable("proxies should already have been unwrapped"); } return SetAndSucceed(Result, makeBool(C, result)); } bool is_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; return SetAndSucceed(Result, makeBool(C, RV.isReflectedTemplate())); } bool is_function_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsFnTemplate = false; if (RV.isReflectedTemplate()) { const TemplateDecl *TD = RV.getReflectedTemplate().getAsTemplateDecl(); IsFnTemplate = isa(TD); } return SetAndSucceed(Result, makeBool(C, IsFnTemplate)); } bool is_variable_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsVarTemplate = false; if (RV.isReflectedTemplate()) { const TemplateDecl *TD = RV.getReflectedTemplate().getAsTemplateDecl(); IsVarTemplate = isa(TD); } return SetAndSucceed(Result, makeBool(C, IsVarTemplate)); } bool is_class_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsClsTemplate = false; if (RV.isReflectedTemplate()) { const TemplateDecl *TD = RV.getReflectedTemplate().getAsTemplateDecl(); IsClsTemplate = isa(TD); } return SetAndSucceed(Result, makeBool(C, IsClsTemplate)); } bool is_alias_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsAliasTemplate = false; if (RV.isReflectedTemplate()) { const TemplateDecl *TD = RV.getReflectedTemplate().getAsTemplateDecl(); IsAliasTemplate = TD->isTypeAlias(); } return SetAndSucceed(Result, makeBool(C, IsAliasTemplate)); } bool is_conversion_function_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsConversionTemplate = false; if (RV.isReflectedTemplate()) { const TemplateDecl *TD = RV.getReflectedTemplate().getAsTemplateDecl(); if (auto *FTD = dyn_cast(TD)) IsConversionTemplate = isa(FTD->getTemplatedDecl()); } return SetAndSucceed(Result, makeBool(C, IsConversionTemplate)); } bool is_operator_function_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsOperatorTemplate = false; if (RV.isReflectedTemplate()) { const TemplateDecl *TD = RV.getReflectedTemplate().getAsTemplateDecl(); if (auto *FTD = dyn_cast(TD)) IsOperatorTemplate = (FTD->getTemplatedDecl()->getOverloadedOperator() != OO_None); } return SetAndSucceed(Result, makeBool(C, IsOperatorTemplate)); } bool is_literal_operator_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsLiteralOperator = false; if (RV.isReflectedTemplate()) { const TemplateDecl *TD = RV.getReflectedTemplate().getAsTemplateDecl(); if (auto *FTD = dyn_cast(TD)) IsLiteralOperator = FTD->getDeclName().getNameKind() == DeclarationName::CXXLiteralOperatorName; } return SetAndSucceed(Result, makeBool(C, IsLiteralOperator)); } bool is_constructor_template(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsCtorTemplate = false; if (RV.isReflectedTemplate()) { const TemplateDecl *TD = RV.getReflectedTemplate().getAsTemplateDecl(); if (auto *FTD = dyn_cast(TD)) IsCtorTemplate = isa(FTD->getTemplatedDecl()); } return SetAndSucceed(Result, makeBool(C, IsCtorTemplate)); } bool is_concept(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsConcept = false; if (RV.isReflectedTemplate()) IsConcept = isa(RV.getReflectedTemplate().getAsTemplateDecl()); return SetAndSucceed(Result, makeBool(C, IsConcept)); } bool is_structured_binding(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) result = isa(RV.getReflectedDecl()); return SetAndSucceed(Result, makeBool(C, result)); } bool is_value(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; return SetAndSucceed(Result, makeBool(C, RV.isReflectedValue())); } bool is_object(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsObject = RV.isReflectedObject(); if (RV.isReflectedDecl()) IsObject = isa(RV.getReflectedDecl()); return SetAndSucceed(Result, makeBool(C, IsObject)); } bool has_template_arguments(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { QualType QT = RV.getReflectedType(); bool result = isTemplateSpecialization(QT); return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::Declaration: { bool result = false; Decl *D = RV.getReflectedDecl(); if (auto *FD = dyn_cast(D)) result = (FD->getTemplateSpecializationArgs() != nullptr); else if (auto *VTSD = dyn_cast(D)) result = VTSD->getTemplateArgs().size() > 0; return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return SetAndSucceed(Result, makeBool(C, false)); } llvm_unreachable("unknown reflection kind"); } bool has_default_member_initializer(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool HasInitializer = false; if (RV.isReflectedDecl()) if (auto *FD = dyn_cast(RV.getReflectedDecl())) HasInitializer = FD->hasInClassInitializer(); return SetAndSucceed(Result, makeBool(C, HasInitializer)); } bool is_conversion_function(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsConversion = false; if (RV.isReflectedDecl()) IsConversion = isa(RV.getReflectedDecl()); return SetAndSucceed(Result, makeBool(C, IsConversion)); } bool is_operator_function(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsOperator = false; if (RV.isReflectedDecl()) if (auto *FD = dyn_cast(RV.getReflectedDecl())) IsOperator = (FD->getOverloadedOperator() != OO_None); return SetAndSucceed(Result, makeBool(C, IsOperator)); } bool is_literal_operator(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsLiteralOperator = false; if (RV.isReflectedDecl()) if (auto *FD = dyn_cast(RV.getReflectedDecl())) IsLiteralOperator = FD->getDeclName().getNameKind() == DeclarationName::CXXLiteralOperatorName; return SetAndSucceed(Result, makeBool(C, IsLiteralOperator)); } bool is_constructor(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: case ReflectionKind::Template: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Declaration: { bool result = isa(RV.getReflectedDecl()); return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::EntityProxy: llvm_unreachable("proxies should already have been unwrapped"); } llvm_unreachable("invalid reflection type"); } bool is_default_constructor(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) if (auto *CtorD = dyn_cast(RV.getReflectedDecl())) result = CtorD->isDefaultConstructor(); return SetAndSucceed(Result, makeBool(C, result)); } bool is_copy_constructor(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) if (auto *CtorD = dyn_cast(RV.getReflectedDecl())) result = CtorD->isCopyConstructor(); return SetAndSucceed(Result, makeBool(C, result)); } bool is_move_constructor(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) if (auto *CtorD = dyn_cast(RV.getReflectedDecl())) result = CtorD->isMoveConstructor(); return SetAndSucceed(Result, makeBool(C, result)); } bool is_assignment(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) if (auto *FD = dyn_cast(RV.getReflectedDecl())) result = (FD->getOverloadedOperator() == OO_Equal); return SetAndSucceed(Result, makeBool(C, result)); } bool is_copy_assignment(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) if (auto *MD = dyn_cast(RV.getReflectedDecl())) result = MD->isCopyAssignmentOperator(); return SetAndSucceed(Result, makeBool(C, result)); } bool is_move_assignment(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedDecl()) if (auto *MD = dyn_cast(RV.getReflectedDecl())) result = MD->isMoveAssignmentOperator(); return SetAndSucceed(Result, makeBool(C, result)); } bool is_destructor(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Declaration: { bool result = isa(RV.getReflectedDecl()); return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::EntityProxy: llvm_unreachable("proxies should already have been unwrapped"); } llvm_unreachable("invalid reflection type"); } bool is_special_member_function(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return SetAndSucceed(Result, makeBool(C, false)); case ReflectionKind::Declaration: { bool IsSpecial = false; if (auto *FD = dyn_cast(RV.getReflectedDecl())) IsSpecial = isSpecialMember(FD); return SetAndSucceed(Result, makeBool(C, IsSpecial)); } case ReflectionKind::Template: { bool result = false; TemplateDecl *TDecl = RV.getReflectedTemplate().getAsTemplateDecl(); if (auto *FTD = dyn_cast(TDecl)) result = isSpecialMember(FTD->getTemplatedDecl()); return SetAndSucceed(Result, makeBool(C, result)); } case ReflectionKind::EntityProxy: llvm_unreachable("proxies should already have been unwrapped"); } llvm_unreachable("invalid reflection type"); } bool is_user_provided(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsUserProvided = false; if (RV.isReflectedDecl()) if (auto *FD = dyn_cast(RV.getReflectedDecl())) { FD = cast(FD->getFirstDecl()); IsUserProvided = !(FD->isImplicit() || FD->isDeleted() || FD->isDefaulted()); } return SetAndSucceed(Result, makeBool(C, IsUserProvided)); } bool is_user_declared(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool IsUserDeclared = false; if (RV.isReflectedDecl()) if (auto *FD = dyn_cast(RV.getReflectedDecl())) { FD = cast(FD->getFirstDecl()); IsUserDeclared = !(FD->isImplicit()); } return SetAndSucceed(Result, makeBool(C, IsUserDeclared)); } bool reflect_result(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); APValue ArgTy; if (!Evaluator(ArgTy, Args[0], true)) return true; assert(ArgTy.isReflectedType()); bool IsLValue = isa(ArgTy.getReflectedType()); if (!IsLValue && !ArgTy.getReflectedType()->isStructuralType()) return Diagnoser(Range.getBegin(), diag::metafn_value_not_structural_type) << ArgTy.getReflectedType() << Range; APValue Arg; if (!Evaluator(Arg, Args[1], !IsLValue)) return true; // Construct an expression whose result is 'Arg', and evaluate it to check if // it's an allowed result of a constant template argument. // // This is just a hack to get 'CheckConstantExpression' in ExprConstant.cpp // called on 'Arg', to diagnose cases like string literals and temporaries // that aren't allowed in template arguments. // // The expression is constructed in three layers: // - A ConstantExpr to hold 'Arg' // - An OpaqueValueExpr to act as the ConstantExpr's subexpression (we can // otherwise ICE when e.g., checking source location of the ConstantExpr) // - An OpaqueValueExpr wrapper around the ConstantExpr to prevent // EvaluateAsConstantExpr from grabbing 'Arg' and short-circuiting the // evaluation (and, more imporantly, the result validation). Expr *OVE = new (C) OpaqueValueExpr(Range.getBegin(), Args[1]->getType(), IsLValue ? VK_LValue : VK_PRValue); { Expr *CE = ConstantExpr::Create(C, OVE, Arg); OVE = new (C) OpaqueValueExpr(Range.getBegin(), Args[1]->getType(), CE->getValueKind(), OK_Ordinary, CE); } { Expr::EvalResult Discarded; ConstantExprKind CEKind = (OVE->getType()->isRecordType() && !IsLValue) ? ConstantExprKind::ClassTemplateArgument : ConstantExprKind::NonClassTemplateArgument; if (!OVE->EvaluateAsConstantExpr(Discarded, C, CEKind)) return Diagnoser(Range.getBegin(), diag::metafn_result_not_representable) << (IsLValue ? 1 : 0) << Range; } // If this is an lvalue to a function, promote the result to reflect // the declaration. if (OVE->getType()->isFunctionType() && Arg.isLValue() && Arg.getLValueOffset().isZero()) if (!Arg.hasLValuePath() || Arg.getLValuePath().size() == 0) if (APValue::LValueBase LVBase = Arg.getLValueBase(); LVBase.is()) return SetAndSucceed( Result, makeReflection( const_cast(LVBase.get()))); QualType ReflTy = ArgTy.getReflectedType(); if (!IsLValue && ReflTy->isRecordType()) { auto *TPO = C.getTemplateParamObjectDecl(ReflTy, Arg); Arg = APValue(APValue::LValueBase{TPO}, CharUnits::Zero(), {}, false, false); ReflTy = QualType{}; } return SetAndSucceed(Result, Arg.Lift(ReflTy)); } bool data_member_spec(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); APValue Scratch; size_t ArgIdx = 0; // Extract the data member type. if (!Evaluator(Scratch, Args[ArgIdx++], true) || !Scratch.isReflectedType()) return true; QualType MemberTy = Scratch.getReflectedType(); // Evaluate whether a member name was provided. std::optional Name; if (!Evaluator(Scratch, Args[ArgIdx++], true)) return true; // Evaluate the given name. Miserably inefficient, but gets the job done. if (static_cast(Scratch.getInt().getExtValue())) { // Evaluate 'name' length. if (!Evaluator(Scratch, Args[ArgIdx++], true)) return true; size_t nameLen = Scratch.getInt().getExtValue(); Name.emplace(nameLen, '\0'); // Evaluate the character type. if (!Evaluator(Scratch, Args[ArgIdx++], true)) return true; QualType CharTy = Scratch.getReflectedType(); // Evaluate the data contents. for (uint64_t k = 0; k < nameLen; ++k) { llvm::APInt Idx(C.getTypeSize(C.getSizeType()), k, false); Expr *Synthesized = IntegerLiteral::Create(C, Idx, C.getSizeType(), Args[ArgIdx]->getExprLoc()); Synthesized = new (C) ArraySubscriptExpr(Args[ArgIdx], Synthesized, CharTy, VK_LValue, OK_Ordinary, Range.getBegin()); if (Synthesized->isValueDependent() || Synthesized->isTypeDependent()) return true; if (!Evaluator(Scratch, Synthesized, true)) return true; (*Name)[k] = static_cast(Scratch.getInt().getExtValue()); } ArgIdx++; } else { ArgIdx += 3; } // Validate the name as an identifier. if (Name) { Lexer Lex(Range.getBegin(), C.getLangOpts(), Name->data(), Name->data(), Name->data() + Name->size(), false); if (!Lex.validateIdentifier(*Name)) return Diagnoser(Range.getBegin(), diag::metafn_name_invalid_identifier) << *Name << Range; } // Evaluate whether an alignment was provided. std::optional Alignment; if (!Evaluator(Scratch, Args[ArgIdx++], true)) return true; if (static_cast(Scratch.getInt().getExtValue())) { // Evaluate 'alignment' value. if (!Evaluator(Scratch, Args[ArgIdx], true)) return true; int alignment = Scratch.getInt().getExtValue(); if (alignment < 0) return true; Alignment = static_cast(alignment); } ArgIdx++; // Evaluate whether a bit width was provided. std::optional BitWidth; if (!Evaluator(Scratch, Args[ArgIdx++], true)) return true; if (static_cast(Scratch.getInt().getExtValue())) { // Evaluate 'width' value. if (!Evaluator(Scratch, Args[ArgIdx], true)) return true; int width = Scratch.getInt().getExtValue(); if (width < 0) return true; BitWidth = static_cast(width); } ArgIdx++; // Evaluate whether the "no_unique_address" attribute should apply. if (!Evaluator(Scratch, Args[ArgIdx++], true)) return true; bool NoUniqueAddress = Scratch.getInt().getBoolValue(); ArgIdx++; TagDataMemberSpec *TDMS = new (C) TagDataMemberSpec { MemberTy, Name, Alignment, BitWidth, NoUniqueAddress }; return SetAndSucceed(Result, makeReflection(TDMS)); } bool define_aggregate(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); APValue Scratch; if (!Evaluator(Scratch, Args[0], true)) return true; if (!Scratch.isReflectedType()) return DiagnoseReflectionKind(Diagnoser, Range, "a class type", DescriptionOf(Scratch)); QualType ToComplete = Scratch.getReflectedType(); if (!ToComplete->isRecordType()) return DiagnoseReflectionKind(Diagnoser, Range, "a class type", DescriptionOf(Scratch)); // Evaluate the number of members provided. if (!Evaluator(Scratch, Args[1], true)) return true; size_t NumMembers = static_cast(Scratch.getInt().getExtValue()); SmallVector MemberSpecs; llvm::FoldingSetNodeID ID; llvm::StringSet<> MemberNames; for (size_t k = 0; k < NumMembers; ++k) { // Extract the reflection from the list of member specs. llvm::APInt Idx(C.getTypeSize(C.getSizeType()), k, false); Expr *Synthesized = IntegerLiteral::Create(C, Idx, C.getSizeType(), Args[2]->getExprLoc()); Synthesized = new (C) ArraySubscriptExpr(Args[2], Synthesized, C.MetaInfoTy, VK_LValue, OK_Ordinary, Range.getBegin()); if (Synthesized->isValueDependent() || Synthesized->isTypeDependent()) return true; if (!Evaluator(Scratch, Synthesized, true)) return true; if (!Scratch.isReflectedDataMemberSpec()) return DiagnoseReflectionKind(Diagnoser, Range, "a description of a data member", DescriptionOf(Scratch)); MemberSpecs.push_back(Scratch.getReflectedDataMemberSpec()); Scratch.Profile(ID); if (MemberSpecs.back()->Name && !MemberNames.insert(*MemberSpecs.back()->Name).second) return Diagnoser(Range.getBegin(), diag::metafn_duplicate_member_names) << *MemberSpecs.back()->Name << Range; } unsigned MemberSpecHash = ID.ComputeHash(); CXXRecordDecl *IncompleteDecl; { NamedDecl *ND; if (!ToComplete->isIncompleteType(&ND)) { // NOTE: Uncomment following lines for 'define_aggregate' idempotency. /*unsigned PriorHash; if (C.checkClassMemberSpecHash(ToComplete, PriorHash) && MemberSpecHash == PriorHash) return SetAndSucceed(Result, makeReflection(ToComplete)); else*/ return Diagnoser(Range.getBegin(), diag::metafn_already_complete_type) << ToComplete << Range; } IncompleteDecl = cast(ND); } if (!AllowInjection) return Diagnoser(Range.getBegin(), diag::metafn_injected_decl_non_plainly_consteval); CXXRecordDecl *Definition = Meta.DefineAggregate(IncompleteDecl, MemberSpecs, ContainingDecl, Range.getBegin()); if (!Definition) return true; C.recordClassMemberSpecHash(ToComplete, MemberSpecHash); return SetAndSucceed(Result, makeReflection(ToComplete)); } bool offset_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); APValue RV; if (!Evaluator(RV, Args[1], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return DiagnoseReflectionKind(Diagnoser, Range, "a non-static data member", DescriptionOf(RV)); case ReflectionKind::Declaration: { if (const FieldDecl *FD = dyn_cast(RV.getReflectedDecl())) { size_t Offset = getBitOffsetOfField(C, FD) / C.getTypeSize(C.CharTy); return SetAndSucceed(Result, APValue(C.MakeIntValue(Offset, ResultTy))); } return DiagnoseReflectionKind(Diagnoser, Range, "a non-static data member", DescriptionOf(RV)); } case ReflectionKind::BaseSpecifier: { CXXBaseSpecifier *Base = RV.getReflectedBaseSpecifier(); if (Base->isVirtual() && Base->getDerived()->isAbstract()) return Diagnoser(Range.getBegin(), diag::metafn_offset_virtual_base_of_abstract) << Range; size_t Offset = getOffsetOfBase(C, Base); return SetAndSucceed(Result, APValue(C.MakeIntValue(Offset, ResultTy))); } } llvm_unreachable("unknown reflection kind"); } bool size_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.getSizeType()); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { QualType QT = RV.getReflectedType(); NamedDecl *typeDecl = findTypeDecl(RV.getReflectedType()); if (typeDecl) Meta.EnsureInstantiated(typeDecl, Range); if (QT->isIncompleteType()) return Diagnoser(Range.getBegin(), diag::metafn_cannot_introspect_type) << 4 << 0 << Range; size_t Sz = C.getTypeSizeInChars(QT).getQuantity(); return SetAndSucceed(Result, APValue(C.MakeIntValue(Sz, C.getSizeType()))); } case ReflectionKind::Object: case ReflectionKind::Value: { QualType QT = RV.getTypeOfReflectedResult(C); size_t Sz = C.getTypeSizeInChars(QT).getQuantity(); return SetAndSucceed(Result, APValue(C.MakeIntValue(Sz, C.getSizeType()))); } case ReflectionKind::Declaration: { ValueDecl *VD = RV.getReflectedDecl(); size_t Sz = C.getTypeSizeInChars(VD->getType()).getQuantity(); return SetAndSucceed(Result, APValue(C.MakeIntValue(Sz, C.getSizeType()))); } case ReflectionKind::DataMemberSpec: { TagDataMemberSpec *TDMS = RV.getReflectedDataMemberSpec(); size_t Sz = C.getTypeSizeInChars(TDMS->Ty).getQuantity(); return SetAndSucceed(Result, APValue(C.MakeIntValue(Sz, C.getSizeType()))); } case ReflectionKind::Null: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 3 << DescriptionOf(RV); } llvm_unreachable("unknown reflection kind"); } bool bit_offset_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); APValue RV; if (!Evaluator(RV, Args[1], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return DiagnoseReflectionKind(Diagnoser, Range, "a non-static data member", DescriptionOf(RV)); case ReflectionKind::Declaration: { if (FieldDecl *FD = dyn_cast(RV.getReflectedDecl())) { size_t Offset = getBitOffsetOfField(C, FD) % C.getTypeSize(C.CharTy); return SetAndSucceed(Result, APValue(C.MakeIntValue(Offset, ResultTy))); } return DiagnoseReflectionKind(Diagnoser, Range, "a non-static data member", DescriptionOf(RV)); } case ReflectionKind::BaseSpecifier: return SetAndSucceed(Result, APValue(C.MakeIntValue(0, ResultTy))); } llvm_unreachable("unknown reflection kind"); } bool bit_size_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.getSizeType()); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { QualType QT = RV.getReflectedType(); NamedDecl *typeDecl = findTypeDecl(RV.getReflectedType()); if (typeDecl) Meta.EnsureInstantiated(typeDecl, Range); if (QT->isIncompleteType()) return Diagnoser(Range.getBegin(), diag::metafn_cannot_introspect_type) << 4 << 0 << Range; size_t Sz = C.getTypeSize(QT); return SetAndSucceed(Result, APValue(C.MakeIntValue(Sz, C.getSizeType()))); } case ReflectionKind::Object: case ReflectionKind::Value: { size_t Sz = C.getTypeSize(RV.getTypeOfReflectedResult(C)); return SetAndSucceed(Result, APValue(C.MakeIntValue(Sz, C.getSizeType()))); } case ReflectionKind::Declaration: { const ValueDecl *VD = cast(RV.getReflectedDecl()); size_t Sz = C.getTypeSize(VD->getType()); if (const FieldDecl *FD = dyn_cast(VD)) if (FD->isBitField()) Sz = FD->getBitWidthValue(); return SetAndSucceed(Result, APValue(C.MakeIntValue(Sz, C.getSizeType()))); } case ReflectionKind::DataMemberSpec: { TagDataMemberSpec *TDMS = RV.getReflectedDataMemberSpec(); size_t Sz = TDMS->BitWidth.value_or(C.getTypeSize(TDMS->Ty)); return SetAndSucceed(Result, APValue(C.MakeIntValue(Sz, C.getSizeType()))); } case ReflectionKind::Null: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 3 << DescriptionOf(RV); } llvm_unreachable("unknown reflection kind"); } bool alignment_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.getSizeType()); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { QualType QT = RV.getReflectedType(); if (QT->isIncompleteType()) return Diagnoser(Range.getBegin(), diag::metafn_cannot_introspect_type) << 3 << 0 << Range; size_t Align = C.getTypeAlignInChars(QT).getQuantity(); return SetAndSucceed(Result, APValue(C.MakeIntValue(Align, C.getSizeType()))); } case ReflectionKind::Object: case ReflectionKind::Value: { QualType QT = RV.getTypeOfReflectedResult(C); size_t Align = C.getTypeAlignInChars(QT).getQuantity(); return SetAndSucceed(Result, APValue(C.MakeIntValue(Align, C.getSizeType()))); } case ReflectionKind::Declaration: { const ValueDecl *VD = cast(RV.getReflectedDecl()); if (const FieldDecl *FD = dyn_cast(VD)) { if (FD->isBitField()) return true; } size_t Align = C.getDeclAlign(VD, false).getQuantity(); return SetAndSucceed(Result, APValue(C.MakeIntValue(Align, C.getSizeType()))); } case ReflectionKind::DataMemberSpec: { TagDataMemberSpec *TDMS = RV.getReflectedDataMemberSpec(); if (TDMS->BitWidth) return true; size_t Align = TDMS->Alignment.value_or( C.getTypeAlignInChars(TDMS->Ty).getQuantity()); return SetAndSucceed(Result, APValue(C.MakeIntValue(Align, C.getSizeType()))); } case ReflectionKind::Null: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 4 << DescriptionOf(RV) << Range; } llvm_unreachable("unknown reflection kind"); } bool get_ith_parameter_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; APValue Sentinel; if (!Evaluator(Sentinel, Args[1], true)) return true; assert(Sentinel.isReflectedType()); APValue Idx; if (!Evaluator(Idx, Args[2], true)) return true; size_t idx = Idx.getInt().getExtValue(); switch (RV.getReflectionKind()) { case ReflectionKind::Type: { if (auto FT = dyn_cast(RV.getReflectedType())) { unsigned numParams = FT->getNumParams(); if (idx >= numParams) return SetAndSucceed(Result, Sentinel); return SetAndSucceed(Result, makeReflection(FT->getParamType(idx))); } return Diagnoser(Range.getBegin(), diag::metafn_cannot_introspect_type) << 2 << 2 << Range; } case ReflectionKind::Declaration: { if (auto FD = dyn_cast(RV.getReflectedDecl())) { unsigned numParams = FD->getNumParams(); if (idx >= numParams) return SetAndSucceed(Result, Sentinel); return SetAndSucceed(Result, makeReflection(FD->getParamDecl(idx))); } return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 5 << DescriptionOf(RV) << Range; } case ReflectionKind::Null: case ReflectionKind::Template: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return true; } return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 5 << DescriptionOf(RV) << Range; } bool has_ellipsis_parameter(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 5 << DescriptionOf(RV) << Range; case ReflectionKind::Type: if (auto *FPT = dyn_cast(RV.getReflectedType())) { bool HasEllipsis = FPT->isVariadic(); return SetAndSucceed(Result, makeBool(C, HasEllipsis)); } return Diagnoser(Range.getBegin(), diag::metafn_cannot_introspect_type) << 2 << 2; case ReflectionKind::Declaration: { if (auto *FD = dyn_cast(RV.getReflectedDecl())) { bool HasEllipsis = FD->getEllipsisLoc().isValid(); return SetAndSucceed(Result, makeBool(C, HasEllipsis)); } return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 5 << DescriptionOf(RV) << Range; } } llvm_unreachable("unknown reflection kind"); } bool has_default_argument(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Parameter: { ParmVarDecl *PVD = getMostRecentParmVarDecl(RV.getReflectedParameter()); return SetAndSucceed(Result, makeBool(C, PVD->hasDefaultArg())); } case ReflectionKind::Declaration: case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return DiagnoseReflectionKind(Diagnoser, Range, "a function parameter", DescriptionOf(RV)); } llvm_unreachable("unknown reflection kind"); } bool is_explicit_object_parameter(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; bool result = false; if (RV.isReflectedParameter()) result = RV.getReflectedParameter()->isExplicitObjectParameter(); return SetAndSucceed(Result, makeBool(C, result)); } bool is_function_parameter(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; return SetAndSucceed(Result, makeBool(C, RV.isReflectedParameter())); } bool return_type_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { if (auto *FPT = dyn_cast(RV.getReflectedType())) { QualType QT = desugarType(FPT->getReturnType(), /*UnwrapAliases=*/ true, /*DropCV=*/false, /*DropRefs=*/false); return SetAndSucceed(Result, makeReflection(QT)); } return Diagnoser(Range.getBegin(), diag::metafn_cannot_introspect_type) << 3 << 2 << Range; } case ReflectionKind::Declaration: if (auto *FD = dyn_cast(RV.getReflectedDecl()); FD && !isa(FD) && !isa(FD)) { QualType QT = desugarType(FD->getReturnType(), /*UnwrapAliases=*/ true, /*DropCV=*/false, /*DropRefs=*/false); return SetAndSucceed(Result, makeReflection(QT)); } [[fallthrough]]; case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::Namespace: case ReflectionKind::EntityProxy: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 6 << DescriptionOf(RV) << Range; } llvm_unreachable("unknown reflection kind"); } bool variable_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; if (!RV.isReflectedParameter()) return DiagnoseReflectionKind(Diagnoser, Range, "a function parameter", DescriptionOf(RV)); ParmVarDecl *PVD = RV.getReflectedParameter(); FunctionDecl *FD = cast(PVD->getDeclContext()); if (Meta.CurrentCtx()->getCanonicalDecl() != FD->getCanonicalDecl()) return true; assert(FD->getDefinition()); PVD = FD->getDefinition()->getParamDecl(PVD->getFunctionScopeIndex()); APValue Var(ReflectionKind::Declaration, PVD); return SetAndSucceed(Result, Var); } bool get_ith_annotation_of(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); auto findAnnotation = [&](Decl *D, size_t idx, APValue Sentinel) { D = D ? D->getMostRecentDecl() : D; while (D) { auto Annots = D->attrs(); for (auto It = Annots.begin(); It != Annots.end(); ++It) if (isa(*It)) if (idx-- == 0) return makeReflection(dyn_cast(*It)); D = D->getPreviousDecl(); } return Sentinel; }; APValue RV; if (!Evaluator(RV, Args[0], true)) return true; APValue Sentinel; if (!Evaluator(Sentinel, Args[1], true)) return true; assert(Sentinel.isReflectedType()); APValue Idx; if (!Evaluator(Idx, Args[2], true)) return true; size_t idx = Idx.getInt().getExtValue(); switch (RV.getReflectionKind()) { case ReflectionKind::Type: { NamedDecl *typeDecl = findTypeDecl(RV.getReflectedType()); if (typeDecl) Meta.EnsureInstantiated(typeDecl, Range); return SetAndSucceed(Result, findAnnotation(typeDecl, idx, Sentinel)); } case ReflectionKind::Declaration: { ValueDecl *VD = RV.getReflectedDecl(); return SetAndSucceed(Result, findAnnotation(VD, idx, Sentinel)); } case ReflectionKind::Namespace: { Decl *D = RV.getReflectedNamespace(); return SetAndSucceed(Result, findAnnotation(D, idx, Sentinel)); } case ReflectionKind::EntityProxy: { Decl *D = RV.getReflectedEntityProxy()->getIntroducer(); return SetAndSucceed(Result, findAnnotation(D, idx, Sentinel)); } // Disallow reflecting annotations of unspecialized templates, as they might // contain a dependent name. case ReflectionKind::Template: /*{ Decl *D = RV.getReflectedTemplate().getAsTemplateDecl()->getTemplatedDecl(); return SetAndSucceed(Result, findAnnotation(D, idx, Sentinel)); }*/ case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_query_property) << 7 << DescriptionOf(RV) << Range; } llvm_unreachable("unknown reflection kind"); } bool is_annotation(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue RV; if (!Evaluator(RV, Args[0], true)) return true; return SetAndSucceed(Result, makeBool(C, RV.isReflectedAnnotation())); } bool annotate(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(Args[1]->getType()->isReflectionType()); assert(ResultTy == C.MetaInfoTy); APValue Appertainee; if (!Evaluator(Appertainee, Args[0], true)) return true; APValue Value; if (!Evaluator(Value, Args[1], true) || !Value.isReflectedValue()) return true; if (!AllowInjection) return Diagnoser(Range.getBegin(), diag::metafn_injected_decl_non_plainly_consteval); switch (Appertainee.getReflectionKind()) { case ReflectionKind::Type: { Decl *D = findTypeDecl(Appertainee.getReflectedType()); if (auto *Annot = Meta.Annotate(D->getMostRecentDecl(), Value, ContainingDecl, Range.getBegin())) return SetAndSucceed(Result, makeReflection(Annot)); return true; } case ReflectionKind::Declaration: { Decl *D = Appertainee.getReflectedDecl(); if (!isa(D)) return true; if (auto *Annot = Meta.Annotate(D->getMostRecentDecl(), Value, ContainingDecl, Range.getBegin())) return SetAndSucceed(Result, makeReflection(Annot)); return true; } case ReflectionKind::Namespace: { Decl *D = Appertainee.getReflectedNamespace(); if (auto *Annot = Meta.Annotate(D->getMostRecentDecl(), Value, ContainingDecl, Range.getBegin())) return SetAndSucceed(Result, makeReflection(Annot)); return true; } case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Template: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: case ReflectionKind::EntityProxy: return Diagnoser(Range.getBegin(), diag::metafn_cannot_annotate) << DescriptionOf(Appertainee) << Range; } llvm_unreachable("unknown reflection kind"); } bool current_access_context(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(ResultTy == C.MetaInfoTy); Decl *Ctx = nullptr; StackLocationExpr *SLE = StackLocationExpr::Create(C, SourceRange(), 1); if (!Evaluator(Result, SLE, true) || !Result.isReflectedDecl()) return true; else if (Ctx = Result.getReflectedDecl(); !Ctx) Ctx = Meta.CurrentCtx(); if (auto *Ctor = dyn_cast(Ctx); Ctor && Ctor->isInheritingConstructor()) Ctx = cast(Ctor->getDeclContext()); if (auto *RD = dyn_cast(Ctx)) return SetAndSucceed(Result, makeReflection(QualType(RD->getTypeForDecl(), 0))); return SetAndSucceed(Result, makeReflection(Ctx)); } bool is_accessible(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(Args[1]->getType()->isReflectionType()); assert(Args[2]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); APValue Scratch; if (!Evaluator(Scratch, Args[1], true) || !Scratch.isReflection()) return true; bool UnconditionalAccess = false; DeclContext *AccessDC = nullptr; switch (Scratch.getReflectionKind()) { case ReflectionKind::Null: UnconditionalAccess = true; break; case ReflectionKind::Type: AccessDC = dyn_cast_or_null( findTypeDecl(Scratch.getReflectedType())); if (!AccessDC) return true; break; case ReflectionKind::Namespace: AccessDC = dyn_cast(Scratch.getReflectedNamespace()); break; case ReflectionKind::Declaration: AccessDC = dyn_cast(Scratch.getReflectedDecl()); break; default: llvm_unreachable("invalid access context"); } CXXRecordDecl *NamingCls = nullptr; if (!Evaluator(Scratch, Args[2], true) || !Scratch.isReflection()) return true; Scratch = MaybeUnproxy(C, Scratch); assert(Scratch.isNullReflection() || Scratch.isReflectedType()); if (Scratch.isReflectedType()) { NamingCls = cast(findTypeDecl(Scratch.getReflectedType())); Meta.EnsureInstantiated(NamingCls, Range); NamingCls = NamingCls->getDefinition(); if (!NamingCls) return true; // TODO(P2996): Diagnostic for naming class. } APValue RV; if (!Evaluator(RV, Args[0], true)) return true; auto validate = [&](Decl *D, CXXRecordDecl *&NamingCls) -> bool { auto *DC = dyn_cast(D->getNonTransparentDeclContext()); if (!NamingCls) NamingCls = DC; if (DC && DC->isBeingDefined()) return Diagnoser(Range.getBegin(), diag::metafn_access_query_class_being_defined) << DC << Range; return false; }; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { NamedDecl *D = findTypeDecl(RV.getReflectedType()); if (validate(D, NamingCls)) return true; else if (!NamingCls) return SetAndSucceed(Result, makeBool(C, true)); bool Accessible = UnconditionalAccess || Meta.IsAccessible(D, AccessDC, NamingCls); return SetAndSucceed(Result, makeBool(C, Accessible)); } case ReflectionKind::Declaration: { ValueDecl *D = RV.getReflectedDecl(); if (validate(D, NamingCls)) return true; else if (!NamingCls) return SetAndSucceed(Result, makeBool(C, true)); bool Accessible = UnconditionalAccess || Meta.IsAccessible(RV.getReflectedDecl(), AccessDC, NamingCls); return SetAndSucceed(Result, makeBool(C, Accessible)); } case ReflectionKind::Template: { TemplateDecl *D = RV.getReflectedTemplate().getAsTemplateDecl(); if (validate(D, NamingCls)) return true; else if (!NamingCls) return SetAndSucceed(Result, makeBool(C, true)); bool Accessible = UnconditionalAccess || Meta.IsAccessible(D, AccessDC, NamingCls); return SetAndSucceed(Result, makeBool(C, Accessible)); } case ReflectionKind::EntityProxy: { UsingShadowDecl *USD = RV.getReflectedEntityProxy(); if (validate(USD, NamingCls)) return true; else if (!NamingCls) return SetAndSucceed(Result, makeBool(C, true)); bool Accessible = UnconditionalAccess || Meta.IsAccessible(USD, AccessDC, NamingCls); return SetAndSucceed(Result, makeBool(C, Accessible)); } case ReflectionKind::BaseSpecifier: { CXXBaseSpecifier *BaseSpec = RV.getReflectedBaseSpecifier(); auto *Base = findTypeDecl(BaseSpec->getType()); assert(Base && "base class has no type declaration?"); QualType BaseTy = BaseSpec->getType(); CXXRecordDecl *DerivedDecl = BaseSpec->getDerived(); if (DerivedDecl->isBeingDefined()) return Diagnoser(Range.getBegin(), diag::metafn_access_query_class_being_defined) << DerivedDecl << Range; QualType DerivedTy(BaseSpec->getDerived()->getTypeForDecl(), 0); CXXBasePathElement bpe = { BaseSpec, BaseSpec->getDerived(), 0 }; CXXBasePath path; path.push_back(bpe); path.Access = BaseSpec->getAccessSpecifier(); bool Accessible = UnconditionalAccess || Meta.IsAccessibleBase(BaseTy, DerivedTy, path, AccessDC, Range.getBegin()); return SetAndSucceed(Result, makeBool(C, Accessible)); } case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return SetAndSucceed(Result, makeBool(C, true)); } llvm_unreachable("invalid reflection type"); } bool is_access_specified(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert(ResultTy == C.BoolTy); auto findAccessSpec = [](Decl *D) -> AccessSpecifier { DeclContext *DC = D->getDeclContext(); for (auto I = DC->decls_begin(); *I != D; ++I) { assert(I != DC->decls_end()); if (auto *ASD = dyn_cast(*I)) return ASD->getAccess(); } return AS_none; }; APValue RV; if (!Evaluator(RV, Args[0], true)) return true; switch (RV.getReflectionKind()) { case ReflectionKind::Type: { bool IsSpecified = false; if (Decl *D = findTypeDecl(RV.getReflectedType())) IsSpecified = findAccessSpec(D) != AS_none; return SetAndSucceed(Result, makeBool(C, IsSpecified)); } case ReflectionKind::Declaration: { bool IsSpecified = findAccessSpec(RV.getReflectedDecl()) != AS_none; return SetAndSucceed(Result, makeBool(C, IsSpecified)); } case ReflectionKind::Template: { Decl *D = RV.getReflectedTemplate().getAsTemplateDecl(); bool IsSpecified = findAccessSpec(D) != AS_none; return SetAndSucceed(Result, makeBool(C, IsSpecified)); } case ReflectionKind::EntityProxy: { Decl *D = RV.getReflectedEntityProxy()->getIntroducer(); bool IsSpecified = findAccessSpec(D) != AS_none; return SetAndSucceed(Result, makeBool(C, IsSpecified)); } case ReflectionKind::BaseSpecifier: { CXXBaseSpecifier *Base = RV.getReflectedBaseSpecifier(); bool IsSpecified = (Base->getAccessSpecifierAsWritten() != AS_none); return SetAndSucceed(Result, makeBool(C, IsSpecified)); } case ReflectionKind::Null: case ReflectionKind::Object: case ReflectionKind::Value: case ReflectionKind::Namespace: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return SetAndSucceed(Result, makeBool(C, false)); } llvm_unreachable("invalid reflection type"); } bool is_nonstatic_member_function(ValueDecl *FD) { if (!FD) { return false; } if (dyn_cast(FD)) { return false; } auto *MD = dyn_cast(FD); if (!MD) { // might be a pointer to member function QualType QT = FD->getType(); // check if the type is a pointer to a member if (const MemberPointerType *MPT = QT->getAs()) { QualType PT = MPT->getPointeeType(); // check if the pointee type is a function type if (PT->getAs()) { return true; } } } else { return !MD->isStatic(); } return false; } CXXMethodDecl *getCXXMethodDeclFromDeclRefExpr(DeclRefExpr *DRE, ASTContext &C) { ValueDecl *VD = DRE->getDecl(); if (auto *MD = dyn_cast(VD)) { // method declaration return MD; } else { // pointer to non-static method // validation was done in is_nonstatic_member_function Expr::EvalResult ER; if (!DRE->EvaluateAsRValue(ER, C)) { return nullptr; } APValue Result = ER.Val; if (!Result.isMemberPointer()) { return nullptr; } const ValueDecl *MemberDecl = Result.getMemberPointerDecl(); if (const CXXMethodDecl *MethodDecl = dyn_cast(MemberDecl)) { // get non-const version return const_cast(MethodDecl); } } return nullptr; } bool reflect_invoke(APValue &Result, ASTContext &C, MetaActions &Meta, EvalFn Evaluator, DiagFn Diagnoser, bool AllowInjection, QualType ResultTy, SourceRange Range, ArrayRef Args, Decl *ContainingDecl) { assert(Args[0]->getType()->isReflectionType()); assert( Args[1]->getType()->getPointeeOrArrayElementType()->isReflectionType()); assert(Args[2]->getType()->isIntegerType()); assert( Args[3]->getType()->getPointeeOrArrayElementType()->isReflectionType()); assert(Args[4]->getType()->isIntegerType()); using ReflectionVector = SmallVector; auto UnpackReflectionsIntoVector = [&](ReflectionVector &Out, Expr *DataExpr, Expr *SzExpr) -> bool { APValue Scratch; if (!Evaluator(Scratch, SzExpr, true)) return false; size_t nArgs = Scratch.getInt().getExtValue(); Out.reserve(nArgs); for (uint64_t k = 0; k < nArgs; ++k) { llvm::APInt Idx(C.getTypeSize(C.getSizeType()), k, false); Expr *Synthesized = IntegerLiteral::Create(C, Idx, C.getSizeType(), DataExpr->getExprLoc()); Synthesized = new (C) ArraySubscriptExpr(DataExpr, Synthesized, C.MetaInfoTy, VK_LValue, OK_Ordinary, Range.getBegin()); if (Synthesized->isValueDependent() || Synthesized->isTypeDependent()) return false; if (!Evaluator(Scratch, Synthesized, true) || !Scratch.isReflection()) return false; Scratch = MaybeUnproxy(C, Scratch); Out.push_back(Scratch); } return true; }; APValue FnRefl; if (!Evaluator(FnRefl, Args[0], true)) return true; FnRefl = MaybeUnproxy(C, FnRefl); SmallVector ExplicitTArgs; { SmallVector Reflections; if (!UnpackReflectionsIntoVector(Reflections, Args[1], Args[2])) llvm_unreachable("failed to unpack template arguments from vector?"); if (Reflections.size() > 0 && !FnRefl.isReflectedTemplate()) return DiagnoseReflectionKind(Diagnoser, Range, "a template", DescriptionOf(FnRefl)); SmallVector TArgs; for (APValue RV : Reflections) { if (!CanActAsTemplateArg(RV)) return Diagnoser(Range.getBegin(), diag::metafn_cannot_be_arg) << DescriptionOf(RV) << 1 << Range; TemplateArgument TArg = TArgFromReflection(C, Meta, Evaluator, RV, Range.getBegin()); if (TArg.isNull()) return true; TArgs.push_back(TArg); } expandTemplateArgPacks(TArgs, ExplicitTArgs); } SmallVector ArgExprs; { SmallVector Reflections; if (!UnpackReflectionsIntoVector(Reflections, Args[3], Args[4])) llvm_unreachable("failed to unpack function arguments from vector?"); for (APValue RV : Reflections) { if (RV.isReflectedObject()) { Expr *OVE = new (C) OpaqueValueExpr(Range.getBegin(), RV.getTypeOfReflectedResult(C), VK_LValue); Expr *CE = ConstantExpr::Create(C, OVE, RV.getReflectedObject()); ArgExprs.push_back(CE); } else if (RV.isReflectedValue()) { Expr *OVE = new (C) OpaqueValueExpr(Range.getBegin(), RV.getTypeOfReflectedResult(C), VK_PRValue); Expr *CE = ConstantExpr::Create(C, OVE, RV.getReflectedValue()); ArgExprs.push_back(CE); } else if (RV.isReflectedDecl()) { ValueDecl *D = RV.getReflectedDecl(); ArgExprs.push_back( DeclRefExpr::Create(C, NestedNameSpecifierLoc(), SourceLocation(), D, false, Range.getBegin(), D->getType(), VK_LValue, D, nullptr)); } else { return Diagnoser(Range.getBegin(), diag::metafn_cannot_be_arg) << DescriptionOf(RV) << 0 << Range; } } } Expr *FnRefExpr = nullptr; switch (FnRefl.getReflectionKind()) { case ReflectionKind::Null: case ReflectionKind::Type: case ReflectionKind::Namespace: case ReflectionKind::BaseSpecifier: case ReflectionKind::Parameter: case ReflectionKind::DataMemberSpec: case ReflectionKind::Annotation: return Diagnoser(Range.getBegin(), diag::metafn_cannot_invoke) << DescriptionOf(FnRefl) << Range; case ReflectionKind::Object: { Expr *OVE = new (C) OpaqueValueExpr(Range.getBegin(), FnRefl.getTypeOfReflectedResult(C), VK_LValue); FnRefExpr = ConstantExpr::Create(C, OVE, FnRefl.getReflectedObject()); break; } case ReflectionKind::Value: { Expr *OVE = new (C) OpaqueValueExpr(Range.getBegin(), FnRefl.getTypeOfReflectedResult(C), VK_PRValue); FnRefExpr = ConstantExpr::Create(C, OVE, FnRefl.getReflectedValue()); break; } case ReflectionKind::Declaration: { ValueDecl *D = FnRefl.getReflectedDecl(); Meta.EnsureInstantiated(D, Range); FnRefExpr = DeclRefExpr::Create(C, NestedNameSpecifierLoc(), SourceLocation(), D, false, Range.getBegin(), D->getType(), VK_LValue, D, nullptr); break; } case ReflectionKind::Template: { TemplateDecl *TDecl = FnRefl.getReflectedTemplate().getAsTemplateDecl(); auto *FTD = dyn_cast(TDecl); if (!FTD) { return Diagnoser(Range.getBegin(), diag::metafn_cannot_invoke) << DescriptionOf(FnRefl) << Range; } FunctionDecl *Spec; { bool exclude_first_arg = is_nonstatic_member_function(FTD->getTemplatedDecl()) && ArgExprs.size() > 0; SmallVector ExpandedTArgs; expandTemplateArgPacks(ExplicitTArgs, ExpandedTArgs); ArrayRef ArgView(ArgExprs.begin() + (exclude_first_arg ? 1 : 0), ArgExprs.end()); Spec = Meta.DeduceSpecialization(FTD, ExpandedTArgs, ArgView, Range.getBegin()); if (!Spec) return Diagnoser(Range.getBegin(), diag::metafn_no_specialization_found) << FTD << Range; Meta.EnsureInstantiated(Spec, Range); } FnRefExpr = DeclRefExpr::Create(C, NestedNameSpecifierLoc(), SourceLocation(), Spec, false, Range.getBegin(), Spec->getType(), VK_LValue, Spec, nullptr); break; } case ReflectionKind::EntityProxy: llvm_unreachable("proxies should already have been unwrapped"); } Expr* CallExpr; { auto *DRE = dyn_cast(FnRefExpr); if (DRE && dyn_cast(DRE->getDecl())) { CallExpr = Meta.SynthesizeCallExpr(DRE, ArgExprs); } else { Expr *FnExpr = FnRefExpr; bool handle_member_func = DRE && is_nonstatic_member_function(DRE->getDecl()); if (handle_member_func) { if (ArgExprs.size() < 1) // need to have object as a first argument return Diagnoser(Range.getBegin(), diag::metafn_first_argument_is_not_object) << Range; Expr *ObjExpr = ArgExprs[0]; QualType ObjType = ObjExpr->getType(); if (ObjType->isPointerType()) { ObjType = ObjType->getPointeeType(); // Convert pointer to rvalue (if needed). APValue Val; if (!Evaluator(Val, ObjExpr, true)) return true; ObjExpr = new (C) OpaqueValueExpr(Range.getBegin(), ObjExpr->getType(), VK_PRValue); ObjExpr = ConstantExpr::Create(C, ObjExpr, Val); } if (!ObjType->getAsCXXRecordDecl()) { // first argument is not an object return Diagnoser(Range.getBegin(), diag::metafn_first_argument_is_not_object) << Range; } CXXMethodDecl *MD = getCXXMethodDeclFromDeclRefExpr(DRE, C); if (!MD) { // most likely, non-constexpr pointer to method was passed return true; } APValue ReflMD = makeReflection(MD); CXXReflectExpr *ReflMDExpr = CXXReflectExpr::Create(C, Range.getBegin(), Range, ReflMD); auto ObjClass = ObjType->getAsCXXRecordDecl(); // check that method belongs to class bool IsMethodFromClassOrParent = (MD->getParent() == ObjClass) || ObjClass->isDerivedFrom(MD->getParent()); if (!IsMethodFromClassOrParent) { return Diagnoser(Range.getBegin(), diag::metafn_function_is_not_member_of_object) << Range; } if (MD->getReturnType()->isVoidType()) { // void return type is not supported return Diagnoser(Range.getBegin(), diag::metafn_function_returns_void) << Range; } FnExpr = Meta.SynthesizeDirectMemberAccess(ObjExpr, ReflMDExpr, Range.getBegin()); if (!FnExpr) return true; } MutableArrayRef ArgView( ArgExprs.begin() + (handle_member_func ? 1 : 0), ArgExprs.end()); CallExpr = Meta.SynthesizeCallExpr(FnExpr, ArgView); } } if (!CallExpr) return Diagnoser(Range.getBegin(), diag::metafn_invalid_call_expr) << Range; if (CallExpr->isTypeDependent() || CallExpr->isValueDependent()) return true; if (!CallExpr->getType()->isStructuralType() && !CallExpr->isLValue()) return Diagnoser(Range.getBegin(), diag::metafn_returns_non_structural_type) << CallExpr->getType() << Range; Expr::EvalResult EvalResult; if (!CallExpr->EvaluateAsConstantExpr(EvalResult, C)) return Diagnoser(Range.getBegin(), diag::metafn_invocation_not_constant_expr) << Range; // If this is an lvalue to a function, promote the result to reflect // the declaration. if (CallExpr->getType()->isFunctionType() && EvalResult.Val.getKind() == APValue::LValue && EvalResult.Val.getLValueOffset().isZero()) if (!EvalResult.Val.hasLValuePath() || EvalResult.Val.getLValuePath().size() == 0) if (APValue::LValueBase LVBase = EvalResult.Val.getLValueBase(); LVBase.is()) return SetAndSucceed( Result, makeReflection( const_cast(LVBase.get()))); return SetAndSucceed(Result, EvalResult.Val.Lift(CallExpr->getType())); } } // end namespace clang