diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h --- a/clang/include/clang/AST/DependenceFlags.h +++ b/clang/include/clang/AST/DependenceFlags.h @@ -83,29 +83,126 @@ 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, + // Uses a template parameter, even if it doesn't affect the result. + // Validity depends on the template parameter. + Instantiation = 2, + // Expression type depends on template context. + // Value and Instantiation should also be set. + Type = 4, + // Expression value depends on template context. + // Instantiation should also be set. + Value = 8, + // Depends on template context. + // 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, + + 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::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)){} + + Dependence(TemplateArgumentDependence D) + : V(translate(D, TADependence::UnexpandedPack, UnexpandedPack) | + translate(D, TADependence::Instantiation, Instantiation) | + translate(D, TADependence::Dependent, Dependent)) {} + + Dependence(TemplateNameDependence D) + : V(translate(D, TNDependence::UnexpandedPack, UnexpandedPack) | + translate(D, TNDependence::Instantiation, Instantiation) | + translate(D, TNDependence::Dependent, Dependent)) {} + + TypeDependence type() const { + return translate(V, UnexpandedPack, TypeDependence::UnexpandedPack) | + translate(V, Instantiation, TypeDependence::Instantiation) | + translate(V, Dependent, TypeDependence::Dependent) | + 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); + } + + TemplateArgumentDependence templateArgument() const { + return translate(V, UnexpandedPack, TADependence::UnexpandedPack) | + translate(V, Instantiation, TADependence::Instantiation) | + translate(V, Dependent, TADependence::Dependent); + } + + TemplateNameDependence templateName() const { + return translate(V, UnexpandedPack, TNDependence::UnexpandedPack) | + translate(V, Instantiation, TNDependence::Instantiation) | + translate(V, Dependent, TNDependence::Dependent); + } + +private: + Bits V; + + template + static U translate(T Bits, T FromBit, U ToBit) { + return (Bits & FromBit) ? ToBit : static_cast(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) { - auto D = ExprDependence::None; - if (TA & TemplateArgumentDependence::UnexpandedPack) - D |= ExprDependence::UnexpandedPack; - if (TA & TemplateArgumentDependence::Instantiation) - D |= ExprDependence::Instantiation; - if (TA & TemplateArgumentDependence::Dependent) - D |= ExprDependence::Type | ExprDependence::Value; - return D; + return Dependence(TA).expr(); } -inline ExprDependence toExprDependence(TypeDependence TD) { - // This hack works because TypeDependence and TemplateArgumentDependence - // share the same bit representation, apart from variably-modified. - return toExprDependence(static_cast( - TD & ~TypeDependence::VariablyModified)); +inline ExprDependence toExprDependence(TypeDependence D) { + return Dependence(D).expr(); } -inline ExprDependence toExprDependence(NestedNameSpecifierDependence NSD) { - // This hack works because TypeDependence and TemplateArgumentDependence - // share the same bit representation. - return toExprDependence(static_cast(NSD)) & - ~ExprDependence::TypeValue; +// Note: it's often necessary to strip `Dependent` from qualifiers. +// If V:: refers to the current instantiation, NNS is considered dependent +// but the containing V::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 @@ -121,57 +218,39 @@ // Returned type-dependence will never have VariablyModified set. inline TypeDependence toTypeDependence(ExprDependence D) { - // Supported bits all have the same representation. - return static_cast(D & (ExprDependence::UnexpandedPack | - ExprDependence::Instantiation | - ExprDependence::Type)); + return Dependence(D).type(); } inline TypeDependence toTypeDependence(NestedNameSpecifierDependence D) { - // Supported bits all have the same representation. - return static_cast(D); + return Dependence(D).type(); } inline TypeDependence toTypeDependence(TemplateNameDependence D) { - // Supported bits all have the same representation. - return static_cast(D); + return Dependence(D).type(); } inline TypeDependence toTypeDependence(TemplateArgumentDependence D) { - // Supported bits all have the same representation. - return static_cast(D); + return Dependence(D).type(); } inline NestedNameSpecifierDependence toNestedNameSpecifierDependendence(TypeDependence D) { - // This works because both classes share the same bit representation. - return static_cast( - D & ~TypeDependence::VariablyModified); + return Dependence(D).nestedNameSpecifier(); } inline TemplateArgumentDependence toTemplateArgumentDependence(TypeDependence D) { - // This works because both classes share the same bit representation. - return static_cast( - D & ~TypeDependence::VariablyModified); + return Dependence(D).templateArgument(); } inline TemplateArgumentDependence toTemplateArgumentDependence(TemplateNameDependence D) { - // This works because both classes share the same bit representation. - return static_cast(D); + return Dependence(D).templateArgument(); } inline TemplateArgumentDependence -toTemplateArgumentDependence(ExprDependence ED) { - TemplateArgumentDependence TAD = TemplateArgumentDependence::None; - if (ED & (ExprDependence::Type | ExprDependence::Value)) - TAD |= TemplateArgumentDependence::Dependent; - if (ED & ExprDependence::Instantiation) - TAD |= TemplateArgumentDependence::Instantiation; - if (ED & ExprDependence::UnexpandedPack) - TAD |= TemplateArgumentDependence::UnexpandedPack; - return TAD; +toTemplateArgumentDependence(ExprDependence D) { + return Dependence(D).templateArgument(); } inline TemplateNameDependence toTemplateNameDependence(NestedNameSpecifierDependence D) { - return static_cast(D); + return Dependence(D).templateName(); } LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -370,7 +370,8 @@ auto Deps = ExprDependence::None; if (auto *NNS = E->getQualifier()) - Deps |= toExprDependence(NNS->getDependence()); + Deps |= toExprDependence(NNS->getDependence() & + ~NestedNameSpecifierDependence::Dependent); if (auto *FirstArg = E->getTemplateArgs()) { unsigned NumArgs = E->getNumTemplateArgs(); @@ -590,7 +591,8 @@ D |= turnTypeToValueDependence( toExprDependence(ST->getType()->getDependence())); if (auto *Q = E->getQualifier()) - D |= toExprDependence(Q->getDependence()); + D |= toExprDependence(Q->getDependence() & + ~NestedNameSpecifierDependence::Dependent); return D; } @@ -616,7 +618,8 @@ Deps |= ExprDependence::UnexpandedPack; Deps |= getDependenceInExpr(E->getNameInfo()); if (auto *Q = E->getQualifier()) - Deps |= toExprDependence(Q->getDependence()); + Deps |= toExprDependence(Q->getDependence() & + ~NestedNameSpecifierDependence::Dependent); for (auto *D : E->decls()) { if (D->getDeclContext()->isDependentContext() || isa(D))