| //===--- DependenceFlags.h ------------------------------------------------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| #ifndef LLVM_CLANG_AST_DEPENDENCEFLAGS_H |
| #define LLVM_CLANG_AST_DEPENDENCEFLAGS_H |
| |
| #include "clang/Basic/BitmaskEnum.h" |
| #include "llvm/ADT/BitmaskEnum.h" |
| #include <cstdint> |
| |
| namespace clang { |
| struct ExprDependenceScope { |
| enum ExprDependence : uint8_t { |
| UnexpandedPack = 1, |
| // This expr depends in any way on |
| // - a template parameter, it implies that the resolution of this expr may |
| // cause instantiation to fail |
| // - or an error (often in a non-template context) |
| // |
| // Note that C++ standard doesn't define the instantiation-dependent term, |
| // we follow the formal definition coming from the Itanium C++ ABI, and |
| // extend it to errors. |
| Instantiation = 2, |
| // The type of this expr depends on a template parameter, or an error. |
| Type = 4, |
| // The value of this expr depends on a template parameter, or an error. |
| Value = 8, |
| |
| // clang extension: this expr contains or references an error, and is |
| // considered dependent on how that error is resolved. |
| Error = 16, |
| |
| None = 0, |
| All = 31, |
| |
| TypeValue = Type | Value, |
| TypeInstantiation = Type | Instantiation, |
| ValueInstantiation = Value | Instantiation, |
| TypeValueInstantiation = Type | Value | Instantiation, |
| ErrorDependent = Error | ValueInstantiation, |
| |
| LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Error) |
| }; |
| }; |
| using ExprDependence = ExprDependenceScope::ExprDependence; |
| |
| struct TypeDependenceScope { |
| enum TypeDependence : uint8_t { |
| /// Whether this type contains an unexpanded parameter pack |
| /// (for C++11 variadic templates) |
| UnexpandedPack = 1, |
| /// Whether this type somehow involves |
| /// - a template parameter, even if the resolution of the type does not |
| /// depend on a template parameter. |
| /// - or an error. |
| Instantiation = 2, |
| /// Whether this type |
| /// - is a dependent type (C++ [temp.dep.type]) |
| /// - or it somehow involves an error, e.g. decltype(recovery-expr) |
| Dependent = 4, |
| /// Whether this type is a variably-modified type (C99 6.7.5). |
| VariablyModified = 8, |
| |
| /// Whether this type references an error, e.g. decltype(err-expression) |
| /// yields an error type. |
| Error = 16, |
| |
| None = 0, |
| All = 31, |
| |
| DependentInstantiation = Dependent | Instantiation, |
| |
| LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Error) |
| }; |
| }; |
| using TypeDependence = TypeDependenceScope::TypeDependence; |
| |
| #define LLVM_COMMON_DEPENDENCE(NAME) \ |
| struct NAME##Scope { \ |
| enum NAME : uint8_t { \ |
| UnexpandedPack = 1, \ |
| Instantiation = 2, \ |
| Dependent = 4, \ |
| Error = 8, \ |
| \ |
| None = 0, \ |
| DependentInstantiation = Dependent | Instantiation, \ |
| All = 15, \ |
| \ |
| LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Error) \ |
| }; \ |
| }; \ |
| using NAME = NAME##Scope::NAME; |
| |
| LLVM_COMMON_DEPENDENCE(NestedNameSpecifierDependence) |
| LLVM_COMMON_DEPENDENCE(TemplateNameDependence) |
| LLVM_COMMON_DEPENDENCE(TemplateArgumentDependence) |
| #undef LLVM_COMMON_DEPENDENCE |
| |
| // A combined space of all dependence concepts for all node types. |
| // Used when aggregating dependence of nodes of different types. |
| class Dependence { |
| public: |
| enum Bits : uint8_t { |
| None = 0, |
| |
| // Contains a template parameter pack that wasn't expanded. |
| UnexpandedPack = 1, |
| // Depends on a template parameter or an error in some way. |
| // Validity depends on how the template is instantiated or the error is |
| // resolved. |
| Instantiation = 2, |
| // Expression type depends on template context, or an error. |
| // Value and Instantiation should also be set. |
| Type = 4, |
| // Expression value depends on template context, or an error. |
| // Instantiation should also be set. |
| Value = 8, |
| // Depends on template context, or an error. |
| // The type/value distinction is only meaningful for expressions. |
| Dependent = Type | Value, |
| // Includes an error, and depends on how it is resolved. |
| Error = 16, |
| // Type depends on a runtime value (variable-length array). |
| VariablyModified = 32, |
| |
| // Dependence that is propagated syntactically, regardless of semantics. |
| Syntactic = UnexpandedPack | Instantiation | Error, |
| // Dependence that is propagated semantically, even in cases where the |
| // type doesn't syntactically appear. This currently excludes only |
| // UnexpandedPack. Even though Instantiation dependence is also notionally |
| // syntactic, we also want to propagate it semantically because anything |
| // that semantically depends on an instantiation-dependent entity should |
| // always be instantiated when that instantiation-dependent entity is. |
| Semantic = |
| Instantiation | Type | Value | Dependent | Error | VariablyModified, |
| |
| LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/VariablyModified) |
| }; |
| |
| Dependence() : V(None) {} |
| |
| Dependence(TypeDependence D) |
| : V(translate(D, TypeDependence::UnexpandedPack, UnexpandedPack) | |
| translate(D, TypeDependence::Instantiation, Instantiation) | |
| translate(D, TypeDependence::Dependent, Dependent) | |
| translate(D, TypeDependence::Error, Error) | |
| translate(D, TypeDependence::VariablyModified, VariablyModified)) {} |
| |
| Dependence(ExprDependence D) |
| : V(translate(D, ExprDependence::UnexpandedPack, UnexpandedPack) | |
| translate(D, ExprDependence::Instantiation, Instantiation) | |
| translate(D, ExprDependence::Type, Type) | |
| translate(D, ExprDependence::Value, Value) | |
| translate(D, ExprDependence::Error, Error)) {} |
| |
| Dependence(NestedNameSpecifierDependence D) : |
| V ( translate(D, NNSDependence::UnexpandedPack, UnexpandedPack) | |
| translate(D, NNSDependence::Instantiation, Instantiation) | |
| translate(D, NNSDependence::Dependent, Dependent) | |
| translate(D, NNSDependence::Error, Error)) {} |
| |
| Dependence(TemplateArgumentDependence D) |
| : V(translate(D, TADependence::UnexpandedPack, UnexpandedPack) | |
| translate(D, TADependence::Instantiation, Instantiation) | |
| translate(D, TADependence::Dependent, Dependent) | |
| translate(D, TADependence::Error, Error)) {} |
| |
| Dependence(TemplateNameDependence D) |
| : V(translate(D, TNDependence::UnexpandedPack, UnexpandedPack) | |
| translate(D, TNDependence::Instantiation, Instantiation) | |
| translate(D, TNDependence::Dependent, Dependent) | |
| translate(D, TNDependence::Error, Error)) {} |
| |
| /// Extract only the syntactic portions of this type's dependence. |
| Dependence syntactic() { |
| Dependence Result = *this; |
| Result.V &= Syntactic; |
| return Result; |
| } |
| |
| /// Extract the semantic portions of this type's dependence that apply even |
| /// to uses where the type does not appear syntactically. |
| Dependence semantic() { |
| Dependence Result = *this; |
| Result.V &= Semantic; |
| return Result; |
| } |
| |
| TypeDependence type() const { |
| return translate(V, UnexpandedPack, TypeDependence::UnexpandedPack) | |
| translate(V, Instantiation, TypeDependence::Instantiation) | |
| translate(V, Dependent, TypeDependence::Dependent) | |
| translate(V, Error, TypeDependence::Error) | |
| translate(V, VariablyModified, TypeDependence::VariablyModified); |
| } |
| |
| ExprDependence expr() const { |
| return translate(V, UnexpandedPack, ExprDependence::UnexpandedPack) | |
| translate(V, Instantiation, ExprDependence::Instantiation) | |
| translate(V, Type, ExprDependence::Type) | |
| translate(V, Value, ExprDependence::Value) | |
| translate(V, Error, ExprDependence::Error); |
| } |
| |
| NestedNameSpecifierDependence nestedNameSpecifier() const { |
| return translate(V, UnexpandedPack, NNSDependence::UnexpandedPack) | |
| translate(V, Instantiation, NNSDependence::Instantiation) | |
| translate(V, Dependent, NNSDependence::Dependent) | |
| translate(V, Error, NNSDependence::Error); |
| } |
| |
| TemplateArgumentDependence templateArgument() const { |
| return translate(V, UnexpandedPack, TADependence::UnexpandedPack) | |
| translate(V, Instantiation, TADependence::Instantiation) | |
| translate(V, Dependent, TADependence::Dependent) | |
| translate(V, Error, TADependence::Error); |
| } |
| |
| TemplateNameDependence templateName() const { |
| return translate(V, UnexpandedPack, TNDependence::UnexpandedPack) | |
| translate(V, Instantiation, TNDependence::Instantiation) | |
| translate(V, Dependent, TNDependence::Dependent) | |
| translate(V, Error, TNDependence::Error); |
| } |
| |
| private: |
| Bits V; |
| |
| template <typename T, typename U> |
| static U translate(T Bits, T FromBit, U ToBit) { |
| return (Bits & FromBit) ? ToBit : static_cast<U>(0); |
| } |
| |
| // Abbreviations to make conversions more readable. |
| using NNSDependence = NestedNameSpecifierDependence; |
| using TADependence = TemplateArgumentDependence; |
| using TNDependence = TemplateNameDependence; |
| }; |
| |
| /// Computes dependencies of a reference with the name having template arguments |
| /// with \p TA dependencies. |
| inline ExprDependence toExprDependence(TemplateArgumentDependence TA) { |
| return Dependence(TA).expr(); |
| } |
| inline ExprDependence toExprDependenceForImpliedType(TypeDependence D) { |
| return Dependence(D).semantic().expr(); |
| } |
| inline ExprDependence toExprDependenceAsWritten(TypeDependence D) { |
| return Dependence(D).expr(); |
| } |
| // Note: it's often necessary to strip `Dependent` from qualifiers. |
| // If V<T>:: refers to the current instantiation, NNS is considered dependent |
| // but the containing V<T>::foo likely isn't. |
| inline ExprDependence toExprDependence(NestedNameSpecifierDependence D) { |
| return Dependence(D).expr(); |
| } |
| inline ExprDependence turnTypeToValueDependence(ExprDependence D) { |
| // Type-dependent expressions are always be value-dependent, so we simply drop |
| // type dependency. |
| return D & ~ExprDependence::Type; |
| } |
| inline ExprDependence turnValueToTypeDependence(ExprDependence D) { |
| // Type-dependent expressions are always be value-dependent. |
| if (D & ExprDependence::Value) |
| D |= ExprDependence::Type; |
| return D; |
| } |
| |
| // Returned type-dependence will never have VariablyModified set. |
| inline TypeDependence toTypeDependence(ExprDependence D) { |
| return Dependence(D).type(); |
| } |
| inline TypeDependence toTypeDependence(NestedNameSpecifierDependence D) { |
| return Dependence(D).type(); |
| } |
| inline TypeDependence toTypeDependence(TemplateNameDependence D) { |
| return Dependence(D).type(); |
| } |
| inline TypeDependence toTypeDependence(TemplateArgumentDependence D) { |
| return Dependence(D).type(); |
| } |
| |
| inline TypeDependence toSyntacticDependence(TypeDependence D) { |
| return Dependence(D).syntactic().type(); |
| } |
| inline TypeDependence toSemanticDependence(TypeDependence D) { |
| return Dependence(D).semantic().type(); |
| } |
| |
| inline NestedNameSpecifierDependence |
| toNestedNameSpecifierDependendence(TypeDependence D) { |
| return Dependence(D).nestedNameSpecifier(); |
| } |
| |
| inline TemplateArgumentDependence |
| toTemplateArgumentDependence(TypeDependence D) { |
| return Dependence(D).templateArgument(); |
| } |
| inline TemplateArgumentDependence |
| toTemplateArgumentDependence(TemplateNameDependence D) { |
| return Dependence(D).templateArgument(); |
| } |
| inline TemplateArgumentDependence |
| toTemplateArgumentDependence(ExprDependence D) { |
| return Dependence(D).templateArgument(); |
| } |
| |
| inline TemplateNameDependence |
| toTemplateNameDependence(NestedNameSpecifierDependence D) { |
| return Dependence(D).templateName(); |
| } |
| |
| LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); |
| |
| } // namespace clang |
| #endif |