Skip to content

CWG3122 [temp.dep.constexpr] Inadequate value-dependence for reflect-expressions #808

Closed
cplusplus/draft
#8924

Description

@katzdm

Full name of submitter: Dan Katz

Reference: [temp.dep.constexpr]

Issue description
[temp.dep.constexpr]/7.1.4 says that ^^operand is value-dependent when operand names a dependent member of the current instantiation, e.g.,

template <typename T>
struct TCls {
  static T mem;
  static constexpr info R = type_of(^^mem);  // '^^mem' is value-dependent.
};

This is good, but it doesn't go far enough: If the enclosing template is instead a function template, then the existing conditions for value-dependence fail to apply.

template <typename T>
consteval void f() {
  T v;
  info R = type_of(^^v);
    // not currently value-dependent; really needs to be.
}

Annotations are also affected:

template <int K>
int f() {
  [[=K]] int v;
  return annotations_of(^^v).size();
    // Also not value-dependent, but really ought to be (even though 'v' is neither type nor value dependent).
}

Applying parent_of in such a situation likewise proves a problem. Some of these circumstances would demand that the compiler surface a reflection that represents a dependent type; others become unnecessarily wide IFNDR traps.

Suggested resolution
The reflection of any templated entity (and more: any entity with a declaration in a templated context enclosing the reflect-expression) should be value-dependent.

Modify [temp.dep.constexpr]/7 as follows:

A reflect-expression is value-dependent if

  • it is of the form ^^ reflection-name and either the reflection-name is

    • is a dependent qualified name,
    • is a dependent namespace-name, or
    • is the name of a template parameter , or
    • names a dependent member of the current instantiation ([temp.dep.type]),

    or lookup for the reflection-name finds a declaration that inhabits a scope corresponding to a templated entity,

  • it is of the form ^^ type-id and the type-id denotes a dependent type, or

  • it is of the form ^^ id-expression and the id-expression is value-dependent.

Note that the value-dependent id-expression bullet remains necessary to handle the case when the operand is a template-id (which is not a reflection-name), e.g.,

template <typename T>
static constexpr T zero = 0;

template <typename T>
unsigned f() {
  return size_of(^^zero<T>);
    // 'zero<T>' is a value-dependent id-expression that is not a reflect-expression.
}

Activity

  1. jensmaurer commented on Nov 17, 2025

    @jensmaurer
    Member

    I think declarations inside templated entities declare themselves templated entities.

  2. katzdm commented on Nov 17, 2025

    @katzdm
    Author

    I think declarations inside templated entities declare themselves templated entities.

    I phrased it that way because I think that block-scope functions and extern variables slip past the definition of "template entity".

  3. jensmaurer commented on Nov 17, 2025

    @jensmaurer
    Member

    But we don't (want to) have reflection on those anyway, right?

  4. katzdm commented on Nov 17, 2025

    @katzdm
    Author

    I'm thinking of from within the block scope that the declaration inhabits, e.g.,

    template <int>
    bool f() {
      void g(int a);
      return has_identifier(parameters_of(^^g)[0]);
    }
    
    void g(int b);  // poisons 'has_identifier' for the first parameter
    
    bool b = f<0>();
      // Well-defined as 'false' if '^^g' is value-dependent; IFNDR if it isn't.
  5. jensmaurer commented on Nov 17, 2025

    @jensmaurer
    Member

    That ^^g is ill-formed per the EWG direction for CWG3065.

  6. jensmaurer commented on Nov 17, 2025

    @jensmaurer
    Member
  7. changed the title [-][temp.dep.constexpr] Inadequate value-dependence for reflect-expressions[/-] [+]CWG3122 [temp.dep.constexpr] Inadequate value-dependence for reflect-expressions[/+] on Nov 17, 2025
  8. katzdm commented on Nov 17, 2025

    @katzdm
    Author

    Ah, thanks - missed/forgot that. In that case, "templated entity" covers all cases, but I think it's too broad; we don't want to make reflections that represent non-dependent templates value-dependent:

    template <auto V>
    void f() {
      int v;
      static constexpr auto r = ^^v;  // <- want this to be value-dependent in the template-definition
      static constexpr auto s = ^^::template f;  // <- this is not value-dependent, even though the operand is a templated entity.
    };

    So maybe we stick with the original suggestion? The "declarations" to which it refers will only be those of templated entities, but it will evolve forwards well, if we later loosen the block-scope restrictions.

  9. jensmaurer commented on Nov 19, 2025

    @jensmaurer
    Member

    If we were to go with "a templated entity other than a template", what would be different?
    Anything using a dependent qualified name is already covered.

    template<class T>
    struct S {
      template<class U> struct X;
      void f() {
         static constexpr auto s = ^^X;   // value-dependent?
      }
    };
    

    Do we want this to be value-dependent?

  10. jensmaurer commented on Nov 19, 2025

    @jensmaurer
    Member

    Add-on question: The "inhabits a scope for a templated entity" wording makes the friend case dependent, too:

    template<class T>
    struct S {
      friend void f(int a);
      static constexpr auto s = ^^f;   // value-dependent?
    };
    void f(int b);
    

    I guess we want reliable parameter name poisoning here, so ^^f needs to be value-dependent.

  11. katzdm commented on Nov 19, 2025

    @katzdm
    Author

    Yes, I think it's desirable that both of the above are value-dependent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions