Hey Richard, This change is tripping up a bunch of the bots:
http://lab.llvm.org:8011/builders/clang-cmake-armv8-lld/builds/1397 I'm going to revert it so that we don't leave the bots broken overnight. -Chris > On May 16, 2019, at 6:46 PM, Richard Smith via cfe-commits > <cfe-commits@lists.llvm.org> wrote: > > Author: rsmith > Date: Thu May 16 18:46:05 2019 > New Revision: 360974 > > URL: http://llvm.org/viewvc/llvm-project?rev=360974&view=rev > Log: > Refactor constant evaluation of typeid(T) to track a symbolic type_info > object rather than tracking the originating expression. > > This is groundwork for supporting polymorphic typeid expressions. (Note > that this somewhat regresses our support for DR1968, but it turns out > that that never actually worked anyway, at least in non-trivial cases.) > > Modified: > cfe/trunk/include/clang/AST/APValue.h > cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td > cfe/trunk/lib/AST/APValue.cpp > cfe/trunk/lib/AST/ExprConstant.cpp > cfe/trunk/lib/CodeGen/CGExprConstant.cpp > cfe/trunk/lib/Sema/SemaTemplate.cpp > cfe/trunk/test/CXX/drs/dr19xx.cpp > cfe/trunk/test/Parser/MicrosoftExtensions.cpp > cfe/trunk/test/SemaCXX/builtin-constant-p.cpp > cfe/trunk/test/SemaCXX/typeid.cpp > cfe/trunk/www/cxx_dr_status.html > > Modified: cfe/trunk/include/clang/AST/APValue.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/APValue.h?rev=360974&r1=360973&r2=360974&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/APValue.h (original) > +++ cfe/trunk/include/clang/AST/APValue.h Thu May 16 18:46:05 2019 > @@ -24,14 +24,52 @@ namespace clang { > class AddrLabelExpr; > class ASTContext; > class CharUnits; > + class CXXRecordDecl; > + class Decl; > class DiagnosticBuilder; > class Expr; > class FieldDecl; > - class Decl; > + struct PrintingPolicy; > + class Type; > class ValueDecl; > - class CXXRecordDecl; > - class QualType; > > +/// Symbolic representation of typeid(T) for some type T. > +class TypeInfoLValue { > + const Type *T; > + > +public: > + TypeInfoLValue() : T() {} > + explicit TypeInfoLValue(const Type *T); > + > + const Type *getType() const { return T; } > + explicit operator bool() const { return T; } > + > + void *getOpaqueValue() { return const_cast<Type*>(T); } > + static TypeInfoLValue getFromOpaqueValue(void *Value) { > + TypeInfoLValue V; > + V.T = reinterpret_cast<const Type*>(Value); > + return V; > + } > + > + void print(llvm::raw_ostream &Out, const PrintingPolicy &Policy) const; > +}; > +} > + > +namespace llvm { > +template<> struct PointerLikeTypeTraits<clang::TypeInfoLValue> { > + static void *getAsVoidPointer(clang::TypeInfoLValue V) { > + return V.getOpaqueValue(); > + } > + static clang::TypeInfoLValue getFromVoidPointer(void *P) { > + return clang::TypeInfoLValue::getFromOpaqueValue(P); > + } > + // Validated by static_assert in APValue.cpp; hardcoded to avoid needing > + // to include Type.h. > + static constexpr int NumLowBitsAvailable = 3; > +}; > +} > + > +namespace clang { > /// APValue - This class implements a discriminated union of [uninitialized] > /// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset], > /// [Vector: N * APValue], [Array: N * APValue] > @@ -57,13 +95,18 @@ public: > > class LValueBase { > public: > - typedef llvm::PointerUnion<const ValueDecl *, const Expr *> PtrTy; > + typedef llvm::PointerUnion<const ValueDecl *, const Expr *, > TypeInfoLValue> > + PtrTy; > > - LValueBase() : CallIndex(0), Version(0) {} > + LValueBase() : Local{} {} > > template <class T> > - LValueBase(T P, unsigned I = 0, unsigned V = 0) > - : Ptr(P), CallIndex(I), Version(V) {} > + LValueBase(T P, unsigned I = 0, unsigned V = 0) : Ptr(P), Local{I, V} { > + assert(!is<TypeInfoLValue>() && > + "don't use this constructor to form a type_info lvalue"); > + } > + > + static LValueBase getTypeInfo(TypeInfoLValue LV, QualType TypeInfo); > > template <class T> > bool is() const { return Ptr.is<T>(); } > @@ -78,28 +121,15 @@ public: > > bool isNull() const; > > - explicit operator bool () const; > + explicit operator bool() const; > > - PtrTy getPointer() const { > - return Ptr; > - } > + PtrTy getPointer() const { return Ptr; } > > - unsigned getCallIndex() const { > - return CallIndex; > - } > + unsigned getCallIndex() const; > + unsigned getVersion() const; > + QualType getTypeInfoType() const; > > - void setCallIndex(unsigned Index) { > - CallIndex = Index; > - } > - > - unsigned getVersion() const { > - return Version; > - } > - > - friend bool operator==(const LValueBase &LHS, const LValueBase &RHS) { > - return LHS.Ptr == RHS.Ptr && LHS.CallIndex == RHS.CallIndex && > - LHS.Version == RHS.Version; > - } > + friend bool operator==(const LValueBase &LHS, const LValueBase &RHS); > friend bool operator!=(const LValueBase &LHS, const LValueBase &RHS) { > return !(LHS == RHS); > } > @@ -107,7 +137,14 @@ public: > > private: > PtrTy Ptr; > - unsigned CallIndex, Version; > + struct LocalState { > + unsigned CallIndex, Version; > + }; > + union { > + LocalState Local; > + /// The type std::type_info, if this is a TypeInfoLValue. > + void *TypeInfoType; > + }; > }; > > /// A FieldDecl or CXXRecordDecl, along with a flag indicating whether we > > Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=360974&r1=360973&r2=360974&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Thu May 16 18:46:05 > 2019 > @@ -160,6 +160,9 @@ def note_constexpr_access_static_tempora > "dynamic_cast of}0 temporary " > "is not allowed in a constant expression outside the expression that " > "created the temporary">; > +def note_constexpr_access_unreadable_object : Note< > + "%select{read of|assignment to|increment of|decrement of|member call on|" > + "dynamic_cast of}0 object '%1' whose value is not known">; > def note_constexpr_modify_global : Note< > "a constant expression cannot modify an object that is visible outside " > "that expression">; > > Modified: cfe/trunk/lib/AST/APValue.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/APValue.cpp?rev=360974&r1=360973&r2=360974&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/APValue.cpp (original) > +++ cfe/trunk/lib/AST/APValue.cpp Thu May 16 18:46:05 2019 > @@ -20,6 +20,56 @@ > #include "llvm/Support/raw_ostream.h" > using namespace clang; > > +/// The identity of a type_info object depends on the canonical unqualified > +/// type only. > +TypeInfoLValue::TypeInfoLValue(const Type *T) > + : T(T->getCanonicalTypeUnqualified().getTypePtr()) {} > + > +void TypeInfoLValue::print(llvm::raw_ostream &Out, > + const PrintingPolicy &Policy) const { > + Out << "typeid("; > + QualType(getType(), 0).print(Out, Policy); > + Out << ")"; > +} > + > +static_assert( > + 1 << llvm::PointerLikeTypeTraits<TypeInfoLValue>::NumLowBitsAvailable <= > + alignof(const Type *), > + "Type is insufficiently aligned"); > + > +APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV, > + QualType TypeInfo) { > + LValueBase Base; > + Base.Ptr = LV; > + Base.TypeInfoType = TypeInfo.getAsOpaquePtr(); > + return Base; > +} > + > +unsigned APValue::LValueBase::getCallIndex() const { > + return is<TypeInfoLValue>() ? 0 : Local.CallIndex; > +} > + > +unsigned APValue::LValueBase::getVersion() const { > + return is<TypeInfoLValue>() ? 0 : Local.Version; > +} > + > +QualType APValue::LValueBase::getTypeInfoType() const { > + assert(is<TypeInfoLValue>() && "not a type_info lvalue"); > + return QualType::getFromOpaquePtr(TypeInfoType); > +} > + > +namespace clang { > +bool operator==(const APValue::LValueBase &LHS, > + const APValue::LValueBase &RHS) { > + if (LHS.Ptr != RHS.Ptr) > + return false; > + if (LHS.is<TypeInfoLValue>()) > + return true; > + return LHS.Local.CallIndex == RHS.Local.CallIndex && > + LHS.Local.Version == RHS.Local.Version; > +} > +} > + > namespace { > struct LVBase { > APValue::LValueBase Base; > @@ -60,6 +110,8 @@ llvm::DenseMapInfo<clang::APValue::LValu > > namespace clang { > llvm::hash_code hash_value(const APValue::LValueBase &Base) { > + if (Base.is<TypeInfoLValue>()) > + return llvm::hash_value(Base.getOpaqueValue()); > return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(), > Base.getVersion()); > } > @@ -470,7 +522,9 @@ void APValue::printPretty(raw_ostream &O > > if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) > Out << *VD; > - else { > + else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) { > + TI.print(Out, Ctx.getPrintingPolicy()); > + } else { > assert(Base.get<const Expr *>() != nullptr && > "Expecting non-null Expr"); > Base.get<const Expr*>()->printPretty(Out, nullptr, > @@ -495,6 +549,9 @@ void APValue::printPretty(raw_ostream &O > if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { > Out << *VD; > ElemTy = VD->getType(); > + } else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) { > + TI.print(Out, Ctx.getPrintingPolicy()); > + ElemTy = Base.getTypeInfoType(); > } else { > const Expr *E = Base.get<const Expr*>(); > assert(E != nullptr && "Expecting non-null Expr"); > > Modified: cfe/trunk/lib/AST/ExprConstant.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=360974&r1=360973&r2=360974&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/ExprConstant.cpp (original) > +++ cfe/trunk/lib/AST/ExprConstant.cpp Thu May 16 18:46:05 2019 > @@ -87,6 +87,9 @@ namespace { > return D->getType(); > } > > + if (TypeInfoLValue TI = B.dyn_cast<TypeInfoLValue>()) > + return B.getTypeInfoType(); > + > const Expr *Base = B.get<const Expr*>(); > > // For a materialized temporary, the type of the temporary we materialized > @@ -1783,6 +1786,9 @@ static bool IsGlobalLValue(APValue::LVal > return isa<FunctionDecl>(D); > } > > + if (B.is<TypeInfoLValue>()) > + return true; > + > const Expr *E = B.get<const Expr*>(); > switch (E->getStmtClass()) { > default: > @@ -1800,7 +1806,6 @@ static bool IsGlobalLValue(APValue::LVal > case Expr::PredefinedExprClass: > case Expr::ObjCStringLiteralClass: > case Expr::ObjCEncodeExprClass: > - case Expr::CXXTypeidExprClass: > case Expr::CXXUuidofExprClass: > return true; > case Expr::ObjCBoxedExprClass: > @@ -1878,9 +1883,9 @@ static void NoteLValueLocation(EvalInfo > const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>(); > if (VD) > Info.Note(VD->getLocation(), diag::note_declared_at); > - else > - Info.Note(Base.get<const Expr*>()->getExprLoc(), > - diag::note_constexpr_temporary_here); > + else if (const Expr *E = Base.dyn_cast<const Expr*>()) > + Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here); > + // We have no information to show for a typeid(T) object. > } > > /// Check that this reference or pointer core constant expression is a valid > @@ -3404,7 +3409,7 @@ static CompleteObject findCompleteObject > > if (!Frame) { > if (const MaterializeTemporaryExpr *MTE = > - dyn_cast<MaterializeTemporaryExpr>(Base)) { > + dyn_cast_or_null<MaterializeTemporaryExpr>(Base)) { > assert(MTE->getStorageDuration() == SD_Static && > "should have a frame for a non-global materialized temporary"); > > @@ -3439,7 +3444,13 @@ static CompleteObject findCompleteObject > } else { > if (!IsAccess) > return CompleteObject(LVal.getLValueBase(), nullptr, BaseType); > - Info.FFDiag(E); > + APValue Val; > + LVal.moveInto(Val); > + Info.FFDiag(E, diag::note_constexpr_access_unreadable_object) > + << AK > + << Val.getAsString(Info.Ctx, > + Info.Ctx.getLValueReferenceType(LValType)); > + NoteLValueLocation(Info, LVal.Base); > return CompleteObject(); > } > } else { > @@ -5777,13 +5788,13 @@ public: > // - Literals > // * CompoundLiteralExpr in C (and in global scope in C++) > // * StringLiteral > -// * CXXTypeidExpr > // * PredefinedExpr > // * ObjCStringLiteralExpr > // * ObjCEncodeExpr > // * AddrLabelExpr > // * BlockExpr > // * CallExpr for a MakeStringConstant builtin > +// - typeid(T) expressions, as TypeInfoLValues > // - Locals and temporaries > // * MaterializeTemporaryExpr > // * Any Expr, with a CallIndex indicating the function in which the > temporary > @@ -6018,8 +6029,14 @@ LValueExprEvaluator::VisitCompoundLitera > } > > bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { > - if (!E->isPotentiallyEvaluated()) > - return Success(E); > + if (!E->isPotentiallyEvaluated()) { > + TypeInfoLValue TypeInfo; > + if (E->isTypeOperand()) > + TypeInfo = TypeInfoLValue(E->getTypeOperand(Info.Ctx).getTypePtr()); > + else > + TypeInfo = TypeInfoLValue(E->getExprOperand()->getType().getTypePtr()); > + return Success(APValue::LValueBase::getTypeInfo(TypeInfo, E->getType())); > + } > > Info.FFDiag(E, diag::note_constexpr_typeid_polymorphic) > << E->getExprOperand()->getType() > @@ -6615,9 +6632,11 @@ bool PointerExprEvaluator::VisitBuiltinC > if (const ValueDecl *VD = > OffsetResult.Base.dyn_cast<const ValueDecl*>()) { > BaseAlignment = Info.Ctx.getDeclAlign(VD); > + } else if (const Expr *E = OffsetResult.Base.dyn_cast<const Expr *>()) > { > + BaseAlignment = GetAlignOfExpr(Info, E, UETT_AlignOf); > } else { > - BaseAlignment = GetAlignOfExpr( > - Info, OffsetResult.Base.get<const Expr *>(), UETT_AlignOf); > + BaseAlignment = GetAlignOfType( > + Info, OffsetResult.Base.getTypeInfoType(), UETT_AlignOf); > } > > if (BaseAlignment < Align) { > @@ -8335,6 +8354,10 @@ static bool EvaluateBuiltinConstantPForL > if (!isa<StringLiteral>(E)) > return false; > return LV.getLValueOffset().isZero(); > + } else if (Base.is<TypeInfoLValue>()) { > + // Surprisingly, GCC considers __builtin_constant_p(&typeid(int)) to > + // evaluate to true. > + return true; > } else { > // Any other base is not constant enough for GCC. > return false; > @@ -8399,6 +8422,8 @@ static QualType getObjectType(APValue::L > } else if (const Expr *E = B.get<const Expr*>()) { > if (isa<CompoundLiteralExpr>(E)) > return E->getType(); > + } else if (B.is<TypeInfoLValue>()) { > + return B.getTypeInfoType(); > } > > return QualType(); > > Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=360974&r1=360973&r2=360974&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original) > +++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Thu May 16 18:46:05 2019 > @@ -1735,6 +1735,17 @@ ConstantLValueEmitter::tryEmitBase(const > return nullptr; > } > > + // Handle typeid(T). > + if (TypeInfoLValue TI = base.dyn_cast<TypeInfoLValue>()) { > + llvm::Type *StdTypeInfoPtrTy = > + CGM.getTypes().ConvertType(base.getTypeInfoType())->getPointerTo(); > + llvm::Constant *TypeInfo = > + CGM.GetAddrOfRTTIDescriptor(QualType(TI.getType(), 0)); > + if (TypeInfo->getType() != StdTypeInfoPtrTy) > + TypeInfo = llvm::ConstantExpr::getBitCast(TypeInfo, StdTypeInfoPtrTy); > + return TypeInfo; > + } > + > // Otherwise, it must be an expression. > return Visit(base.get<const Expr*>()); > } > > Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=360974&r1=360973&r2=360974&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) > +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu May 16 18:46:05 2019 > @@ -6424,8 +6424,11 @@ ExprResult Sema::CheckTemplateArgument(N > // -- a string literal > // -- the result of a typeid expression, or > // -- a predefined __func__ variable > - if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) { > - if (isa<CXXUuidofExpr>(E)) { > + APValue::LValueBase Base = Value.getLValueBase(); > + auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>()); > + if (Base && !VD) { > + auto *E = Base.dyn_cast<const Expr *>(); > + if (E && isa<CXXUuidofExpr>(E)) { > Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts()); > break; > } > @@ -6433,8 +6436,6 @@ ExprResult Sema::CheckTemplateArgument(N > << Arg->getSourceRange(); > return ExprError(); > } > - auto *VD = const_cast<ValueDecl *>( > - Value.getLValueBase().dyn_cast<const ValueDecl *>()); > // -- a subobject > if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 && > VD && VD->getType()->isArrayType() && > > Modified: cfe/trunk/test/CXX/drs/dr19xx.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr19xx.cpp?rev=360974&r1=360973&r2=360974&view=diff > ============================================================================== > --- cfe/trunk/test/CXX/drs/dr19xx.cpp (original) > +++ cfe/trunk/test/CXX/drs/dr19xx.cpp Thu May 16 18:46:05 2019 > @@ -167,9 +167,14 @@ namespace dr1959 { // dr1959: 3.9 > #endif > } > > -namespace dr1968 { // dr1968: yes > +namespace dr1968 { // dr1968: no > #if __cplusplus >= 201103L > - static_assert(&typeid(int) == &typeid(int), ""); // expected-error{{not an > integral constant expression}} > + // FIXME: According to DR1968, both of these should be considered > + // non-constant. > + static_assert(&typeid(int) == &typeid(int), ""); > + > + constexpr const std::type_info *f() { return &typeid(int); } > + static_assert(f() == f(), ""); > #endif > } > > > Modified: cfe/trunk/test/Parser/MicrosoftExtensions.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/MicrosoftExtensions.cpp?rev=360974&r1=360973&r2=360974&view=diff > ============================================================================== > --- cfe/trunk/test/Parser/MicrosoftExtensions.cpp (original) > +++ cfe/trunk/test/Parser/MicrosoftExtensions.cpp Thu May 16 18:46:05 2019 > @@ -138,6 +138,8 @@ typedef COM_CLASS_TEMPLATE_REF<struct_wi > COM_CLASS_TEMPLATE_REF<int, __uuidof(struct_with_uuid)> good_template_arg; > > COM_CLASS_TEMPLATE<int, __uuidof(struct_with_uuid)> bad_template_arg; // > expected-error {{non-type template argument of type 'const _GUID' is not a > constant expression}} > +// expected-note@-1 {{read of object '__uuidof(struct_with_uuid)' whose > value is not known}} > +// expected-note@-2 {{temporary created here}} > > namespace PR16911 { > struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid; > > Modified: cfe/trunk/test/SemaCXX/builtin-constant-p.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/builtin-constant-p.cpp?rev=360974&r1=360973&r2=360974&view=diff > ============================================================================== > --- cfe/trunk/test/SemaCXX/builtin-constant-p.cpp (original) > +++ cfe/trunk/test/SemaCXX/builtin-constant-p.cpp Thu May 16 18:46:05 2019 > @@ -130,3 +130,8 @@ constexpr int mutate6(bool mutate) { > static_assert(mutate6(false) == 11); > // Mutation of state outside __builtin_constant_p: evaluates to false. > static_assert(mutate6(true) == 10); > + > +// GCC strangely returns true for the address of a type_info object, despite > it > +// not being a pointer to the start of a string literal. > +namespace std { struct type_info; } > +static_assert(__builtin_constant_p(&typeid(int))); > > Modified: cfe/trunk/test/SemaCXX/typeid.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/typeid.cpp?rev=360974&r1=360973&r2=360974&view=diff > ============================================================================== > --- cfe/trunk/test/SemaCXX/typeid.cpp (original) > +++ cfe/trunk/test/SemaCXX/typeid.cpp Thu May 16 18:46:05 2019 > @@ -6,7 +6,7 @@ void f() > } > > namespace std { > - class type_info; > + struct type_info { const char *name; }; > } > > void g() > @@ -27,3 +27,6 @@ void h(int i) { > typeid(V); // expected-error{{'typeid' of variably modified type > 'char [i]'}} > typeid(char [i]); // expected-error{{'typeid' of variably modified type > 'char [i]'}} > } > + > +// expected-note@+1 {{read of object 'typeid(int).name' whose value is not > known}} > +constexpr const char *name = typeid(int).name; // expected-error {{constant > expression}} > > Modified: cfe/trunk/www/cxx_dr_status.html > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=360974&r1=360973&r2=360974&view=diff > ============================================================================== > --- cfe/trunk/www/cxx_dr_status.html (original) > +++ cfe/trunk/www/cxx_dr_status.html Thu May 16 18:46:05 2019 > @@ -11623,7 +11623,7 @@ and <I>POD class</I></td> > <td><a href="http://wg21.link/cwg1968">1968</a></td> > <td>NAD</td> > <td>Address of <TT>typeid</TT> in constant expressions</td> > - <td class="full" align="center">Yes</td> > + <td class="none" align="center">No</td> > </tr> > <tr class="open" id="1969"> > <td><a href="http://wg21.link/cwg1969">1969</a></td> > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits