diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -1040,9 +1040,6 @@ if (VD && MergeLV(getLVForDecl(VD, computation))) break; } else if (const auto TI = V.getLValueBase().dyn_cast()) { - // FIXME: Claim that typeinfo(T) has the same linkage as T. This isn't - // correct across all ABIs, but for now it shouldn't matter as such - // values aren't permitted within template arguments. if (MergeLV(getLVForType(*TI.getType(), computation))) break; } else if (const Expr *E = V.getLValueBase().dyn_cast()) { @@ -1050,6 +1047,8 @@ // lifetime-extended temporaries. // FIXME: These should be modeled as having the // LifetimeExtendedTemporaryDecl itself as the base. + // FIXME: If we permit Objective-C object literals in template arguments, + // they should not imply internal linkage. auto *MTE = dyn_cast(E); if (!MTE || MTE->getStorageDuration() == SD_FullExpression) return LinkageInfo::internal(); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -421,6 +421,8 @@ void mangleNumber(const llvm::APSInt &I); void mangleNumber(int64_t Number); void mangleFloat(const llvm::APFloat &F); + void mangleFloatLiteral(QualType T, const llvm::APFloat &V); + void mangleFixedPointLiteral(); void mangleFunctionEncoding(GlobalDecl GD); void mangleSeqID(unsigned SeqID); void mangleName(GlobalDecl GD); @@ -1055,6 +1057,20 @@ Out.write(buffer.data(), numCharacters); } +void CXXNameMangler::mangleFloatLiteral(QualType T, const llvm::APFloat &V) { + Out << 'L'; + mangleType(T); + mangleFloat(V); + Out << 'E'; +} + +void CXXNameMangler::mangleFixedPointLiteral() { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, "cannot mangle fixed point literals yet"); + Diags.Report(DiagID); +} + void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) { if (Value.isSigned() && Value.isNegative()) { Out << 'n'; @@ -3944,7 +3960,6 @@ case Expr::PseudoObjectExprClass: case Expr::AtomicExprClass: case Expr::SourceLocExprClass: - case Expr::FixedPointLiteralClass: case Expr::BuiltinBitCastExprClass: { if (!NullOut) { @@ -4518,13 +4533,14 @@ case Expr::FloatingLiteralClass: { const FloatingLiteral *FL = cast(E); - Out << 'L'; - mangleType(FL->getType()); - mangleFloat(FL->getValue()); - Out << 'E'; + mangleFloatLiteral(FL->getType(), FL->getValue()); break; } + case Expr::FixedPointLiteralClass: + mangleFixedPointLiteral(); + break; + case Expr::CharacterLiteralClass: Out << 'L'; mangleType(E->getType()); @@ -4874,8 +4890,9 @@ // Template parameter objects are modeled by reproducing a source form // produced as if by aggregate initialization. - if (auto *TPO = dyn_cast(D)) { + if (A.getParamTypeForDecl()->isRecordType()) { Out << 'X'; + auto *TPO = cast(D); mangleValueInTemplateArg(TPO->getType().getUnqualifiedType(), TPO->getValue()); Out << 'E'; @@ -4921,59 +4938,80 @@ /// Determine whether a given value is equivalent to zero-initialization for /// the purpose of discarding a trailing portion of a 'tl' mangling. -static bool isZeroInitialized(const APValue &V) { - // FIXME: mangleValueInTemplateArg has quadratic time complexity due to using - // this. We could do the same thing in linear time, for example by instead - // mangling the whole value speculatively and retroactively deleting the - // longest trailing part of each 'tl' mangling that is equivalent to zero- - // initialization. +/// +/// Note that this is not in general equivalent to determining whether the +/// value has an all-zeroes bit pattern. +static bool isZeroInitialized(QualType T, const APValue &V) { + // FIXME: mangleValueInTemplateArg has quadratic time complexity in + // pathological cases due to using this, but it's a little awkward + // to do this in linear time in general. switch (V.getKind()) { case APValue::None: case APValue::Indeterminate: case APValue::AddrLabelDiff: return false; - case APValue::Struct: - for (unsigned I = 0, N = V.getStructNumBases(); I != N; ++I) - if (!isZeroInitialized(V.getStructBase(I))) + case APValue::Struct: { + const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); + assert(RD && "unexpected type for record value"); + unsigned I = 0; + for (const CXXBaseSpecifier &BS : RD->bases()) { + if (!isZeroInitialized(BS.getType(), V.getStructBase(I))) return false; - // FIXME: Ignore anonymous bit-fields. - for (unsigned I = 0, N = V.getStructNumFields(); I != N; ++I) - if (!isZeroInitialized(V.getStructField(I))) + ++I; + } + I = 0; + for (const FieldDecl *FD : RD->fields()) { + if (!FD->isUnnamedBitfield() && + !isZeroInitialized(FD->getType(), V.getStructField(I))) return false; + ++I; + } return true; + } case APValue::Union: { - const FieldDecl *FD = V.getUnionField(); - // FIXME: Empty unions are always zero-initialized. - if (!FD || FD->getFieldIndex() != 0) - return false; - return isZeroInitialized(V.getUnionValue()); + const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); + assert(RD && "unexpected type for union value"); + // Zero-initialization zeroes the first non-unnamed-bitfield field, if any. + for (const FieldDecl *FD : RD->fields()) { + if (!FD->isUnnamedBitfield()) + return V.getUnionField() && declaresSameEntity(FD, V.getUnionField()) && + isZeroInitialized(FD->getType(), V.getUnionValue()); + } + // If there are no fields (other than unnamed bitfields), the value is + // necessarily zero-initialized. + return true; } - case APValue::Array: + case APValue::Array: { + QualType ElemT(T->getArrayElementTypeNoTypeQual(), 0); for (unsigned I = 0, N = V.getArrayInitializedElts(); I != N; ++I) - if (!isZeroInitialized(V.getArrayInitializedElt(I))) + if (!isZeroInitialized(ElemT, V.getArrayInitializedElt(I))) return false; - return !V.hasArrayFiller() || isZeroInitialized(V.getArrayFiller()); + return !V.hasArrayFiller() || isZeroInitialized(ElemT, V.getArrayFiller()); + } - case APValue::Vector: + case APValue::Vector: { + const VectorType *VT = T->castAs(); for (unsigned I = 0, N = V.getVectorLength(); I != N; ++I) - if (!isZeroInitialized(V.getVectorElt(I))) + if (!isZeroInitialized(VT->getElementType(), V.getVectorElt(I))) return false; return true; + } case APValue::Int: return !V.getInt(); case APValue::Float: - return V.getFloat().isZero(); + return V.getFloat().isPosZero(); case APValue::FixedPoint: return !V.getFixedPoint().getValue(); case APValue::ComplexFloat: - return V.getComplexFloatReal().isZero() && V.getComplexFloatImag().isZero(); + return V.getComplexFloatReal().isPosZero() && + V.getComplexFloatImag().isPosZero(); case APValue::ComplexInt: return !V.getComplexIntReal() && !V.getComplexIntImag(); @@ -4987,6 +5025,10 @@ } void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V) { + // Ignore all top-level cv-qualifiers, to match GCC. + Qualifiers Quals; + T = getASTContext().getUnqualifiedArrayType(T, Quals); + // Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/63. switch (V.getKind()) { case APValue::None: @@ -5003,31 +5045,34 @@ const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); assert(RD && "unexpected type for record value"); - unsigned NBases = V.getStructNumBases(); - unsigned NFields = V.getStructNumFields(); - // FIXME: Ignore anonymous bit-fields. - while (NFields && isZeroInitialized(V.getStructField(NFields - 1))) - --NFields; - if (!NFields) - while (NBases && isZeroInitialized(V.getStructBase(NBases - 1))) - --NBases; + // Drop trailing zero-initialized elements. + llvm::SmallVector Fields(RD->field_begin(), + RD->field_end()); + while ( + !Fields.empty() && + (Fields.back()->isUnnamedBitfield() || + isZeroInitialized(Fields.back()->getType(), + V.getStructField(Fields.back()->getFieldIndex())))) { + Fields.pop_back(); + } + llvm::ArrayRef Bases(RD->bases_begin(), RD->bases_end()); + if (Fields.empty()) { + while (!Bases.empty() && + isZeroInitialized(Bases.back().getType(), + V.getStructBase(Bases.size() - 1))) + Bases = Bases.drop_back(); + } // ::= tl * E Out << "tl"; mangleType(T); - unsigned BaseIndex = 0; - for (const CXXBaseSpecifier &BS : RD->bases()) { - if (BaseIndex == NBases) - break; - mangleValueInTemplateArg(BS.getType(), V.getStructBase(BaseIndex++)); - } - for (const FieldDecl *FD : RD->fields()) { - if (FD->getFieldIndex() == NFields) - break; - if (FD->isUnnamedBitfield()) + for (unsigned I = 0, N = Bases.size(); I != N; ++I) + mangleValueInTemplateArg(Bases[I].getType(), V.getStructBase(I)); + for (unsigned I = 0, N = Fields.size(); I != N; ++I) { + if (Fields[I]->isUnnamedBitfield()) continue; - mangleValueInTemplateArg(FD->getType(), - V.getStructField(FD->getFieldIndex())); + mangleValueInTemplateArg(Fields[I]->getType(), + V.getStructField(Fields[I]->getFieldIndex())); } Out << 'E'; return; @@ -5048,7 +5093,7 @@ // ::= di Out << "tl"; mangleType(T); - if (!isZeroInitialized(V)) { + if (!isZeroInitialized(T, V)) { Out << "di"; mangleSourceName(FD->getIdentifier()); mangleValueInTemplateArg(FD->getType(), V.getUnionValue()); @@ -5058,17 +5103,16 @@ } case APValue::Array: { - const ArrayType *AT = Context.getASTContext().getAsArrayType(T); - assert(AT && "unexpected type for array value"); + QualType ElemT(T->getArrayElementTypeNoTypeQual(), 0); Out << "tl"; mangleType(T); // Drop trailing zero-initialized elements. unsigned N = V.getArraySize(); - if (!V.hasArrayFiller() || isZeroInitialized(V.getArrayFiller())) { + if (!V.hasArrayFiller() || isZeroInitialized(ElemT, V.getArrayFiller())) { N = V.getArrayInitializedElts(); - while (N && isZeroInitialized(V.getArrayInitializedElt(N - 1))) + while (N && isZeroInitialized(ElemT, V.getArrayInitializedElt(N - 1))) --N; } @@ -5076,7 +5120,7 @@ const APValue &Elem = I < V.getArrayInitializedElts() ? V.getArrayInitializedElt(I) : V.getArrayFiller(); - mangleValueInTemplateArg(AT->getElementType(), Elem); + mangleValueInTemplateArg(ElemT, Elem); } Out << 'E'; return; @@ -5088,7 +5132,7 @@ Out << "tl"; mangleType(T); unsigned N = V.getVectorLength(); - while (N && isZeroInitialized(V.getVectorElt(N - 1))) + while (N && isZeroInitialized(VT->getElementType(), V.getVectorElt(N - 1))) --N; for (unsigned I = 0; I != N; ++I) mangleValueInTemplateArg(VT->getElementType(), V.getVectorElt(I)); @@ -5101,33 +5145,22 @@ return; case APValue::Float: - Out << 'L'; - mangleType(T); - mangleFloat(V.getFloat()); - Out << 'E'; + mangleFloatLiteral(T, V.getFloat()); return; case APValue::FixedPoint: - llvm_unreachable("Fixed point types are disabled for c++"); + mangleFixedPointLiteral(); return; case APValue::ComplexFloat: { const ComplexType *CT = T->castAs(); Out << "tl"; mangleType(T); - if (V.getComplexFloatReal().isNonZero() || - V.getComplexFloatImag().isNonZero()) { - Out << 'L'; - mangleType(CT->getElementType()); - mangleFloat(V.getComplexFloatReal()); - Out << 'E'; - } - if (V.getComplexFloatImag().isNonZero()) { - Out << 'L'; - mangleType(CT->getElementType()); - mangleFloat(V.getComplexFloatImag()); - Out << 'E'; - } + if (!V.getComplexFloatReal().isPosZero() || + !V.getComplexFloatImag().isPosZero()) + mangleFloatLiteral(CT->getElementType(), V.getComplexFloatReal()); + if (!V.getComplexFloatImag().isPosZero()) + mangleFloatLiteral(CT->getElementType(), V.getComplexFloatImag()); Out << 'E'; return; } @@ -5167,7 +5200,7 @@ // a cast, because L 0 E means something else. Out << "rc"; mangleType(T); - Out << "Li0EE"; + Out << "Li0E"; } else { Out << "L"; mangleType(T); diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -308,12 +308,17 @@ void mangleName(const NamedDecl *ND); void mangleFunctionEncoding(const FunctionDecl *FD, bool ShouldMangle); void mangleVariableEncoding(const VarDecl *VD); - void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD); + void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD, + StringRef Prefix = "$"); void mangleMemberFunctionPointer(const CXXRecordDecl *RD, - const CXXMethodDecl *MD); + const CXXMethodDecl *MD, + StringRef Prefix = "$"); void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, const MethodVFTableLocation &ML); void mangleNumber(int64_t Number); + void mangleNumber(llvm::APSInt Number); + void mangleFloat(llvm::APFloat Number); + void mangleBits(llvm::APInt Number); void mangleTagTypeKind(TagTypeKind TK); void mangleArtificialTagType(TagTypeKind TK, StringRef UnqualifiedName, ArrayRef NestedNames = None); @@ -388,6 +393,8 @@ const TemplateArgumentList &TemplateArgs); void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA, const NamedDecl *Parm); + void mangleTemplateArgValue(QualType T, const APValue &V, + bool WithScalarType = true); void mangleObjCProtocol(const ObjCProtocolDecl *PD); void mangleObjCLifetime(const QualType T, Qualifiers Quals, @@ -504,10 +511,8 @@ // 'const struct __s_GUID'. Out << "3U__s_GUID@@B"; else if (isa(D)) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle template parameter objects yet"); - Diags.Report(SourceLocation(), DiagID); + // Template parameter objects don't get a ; their type is + // specified as part of their value. } else llvm_unreachable("Tried to mangle unexpected NamedDecl!"); } @@ -599,7 +604,8 @@ } void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD, - const ValueDecl *VD) { + const ValueDecl *VD, + StringRef Prefix) { // ::= // ::= $F // ::= $G @@ -631,7 +637,7 @@ case MSInheritanceModel::Unspecified: Code = 'G'; break; } - Out << '$' << Code; + Out << Prefix << Code; mangleNumber(FieldOffset); @@ -646,7 +652,8 @@ void MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD, - const CXXMethodDecl *MD) { + const CXXMethodDecl *MD, + StringRef Prefix) { // ::= $1? // ::= $H? // ::= $I? @@ -668,7 +675,7 @@ uint64_t VBTableOffset = 0; uint64_t VBPtrOffset = 0; if (MD) { - Out << '$' << Code << '?'; + Out << Prefix << Code << '?'; if (MD->isVirtual()) { MicrosoftVTableContext *VTContext = cast(getASTContext().getVTableContext()); @@ -691,12 +698,12 @@ } else { // Null single inheritance member functions are encoded as a simple nullptr. if (IM == MSInheritanceModel::Single) { - Out << "$0A@"; + Out << Prefix << "0A@"; return; } if (IM == MSInheritanceModel::Unspecified) VBTableOffset = -1; - Out << '$' << Code; + Out << Prefix << Code; } if (inheritanceModelHasNVOffsetField(/*IsMemberFunction=*/true, IM)) @@ -735,32 +742,63 @@ } void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) { + mangleNumber(llvm::APSInt(llvm::APInt(64, Number), /*IsUnsigned*/false)); +} + +void MicrosoftCXXNameMangler::mangleNumber(llvm::APSInt Number) { + // MSVC never mangles any integer wider than 64 bits. In general it appears + // to convert every integer to signed 64 bit before mangling (including + // unsigned 64 bit values). Do the same, but preserve bits beyond the bottom + // 64. + llvm::APInt Value = + Number.isSigned() ? Number.sextOrSelf(64) : Number.zextOrSelf(64); + // ::= A@ # when Number == 0 // ::= # when 1 <= Number <= 10 // ::= + @ # when Number >= 10 // // ::= [?] - uint64_t Value = static_cast(Number); - if (Number < 0) { + if (Value.isNegative()) { Value = -Value; Out << '?'; } + mangleBits(Value); +} +void MicrosoftCXXNameMangler::mangleFloat(llvm::APFloat Number) { + using llvm::APFloat; + + switch (APFloat::SemanticsToEnum(Number.getSemantics())) { + case APFloat::S_IEEEsingle: Out << 'A'; break; + case APFloat::S_IEEEdouble: Out << 'B'; break; + + // The following are all Clang extensions. We try to pick manglings that are + // unlikely to conflict with MSVC's scheme. + case APFloat::S_IEEEhalf: Out << 'V'; break; + case APFloat::S_BFloat: Out << 'W'; break; + case APFloat::S_x87DoubleExtended: Out << 'X'; break; + case APFloat::S_IEEEquad: Out << 'Y'; break; + case APFloat::S_PPCDoubleDouble: Out << 'Z'; break; + } + + mangleBits(Number.bitcastToAPInt()); +} + +void MicrosoftCXXNameMangler::mangleBits(llvm::APInt Value) { if (Value == 0) Out << "A@"; - else if (Value >= 1 && Value <= 10) + else if (Value.uge(1) && Value.ule(10)) Out << (Value - 1); else { // Numbers that are not encoded as decimal digits are represented as nibbles // in the range of ASCII characters 'A' to 'P'. // The number 0x123450 would be encoded as 'BCDEFA' - char EncodedNumberBuffer[sizeof(uint64_t) * 2]; - MutableArrayRef BufferRef(EncodedNumberBuffer); - MutableArrayRef::reverse_iterator I = BufferRef.rbegin(); - for (; Value != 0; Value >>= 4) - *I++ = 'A' + (Value & 0xf); - Out.write(I.base(), I - BufferRef.rbegin()); + llvm::SmallString<32> EncodedNumberBuffer; + for (; Value != 0; Value.lshrInPlace(4)) + EncodedNumberBuffer.push_back('A' + (Value & 0xf).getZExtValue()); + std::reverse(EncodedNumberBuffer.begin(), EncodedNumberBuffer.end()); + Out.write(EncodedNumberBuffer.data(), EncodedNumberBuffer.size()); Out << '@'; } } @@ -914,6 +952,13 @@ break; } + if (const auto *TPO = dyn_cast(ND)) { + Out << "?__N"; + mangleTemplateArgValue(TPO->getType().getUnqualifiedType(), + TPO->getValue()); + break; + } + // We must have an anonymous struct. const TagDecl *TD = cast(ND); if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) { @@ -1382,10 +1427,7 @@ Out << "0"; - if (Value.isSigned()) - mangleNumber(Value.getSExtValue()); - else - mangleNumber(Value.getZExtValue()); + mangleNumber(Value); } void MicrosoftCXXNameMangler::mangleExpression( @@ -1433,6 +1475,7 @@ // ::= // ::= $E? // ::= $1? + // ::= $2 # class NTTP // ::= $0A@ // ::= @@ -1462,6 +1505,11 @@ mangleName(FD); mangleFunctionEncoding(FD, /*ShouldMangle=*/true); } + } else if (TA.getParamTypeForDecl()->isRecordType()) { + Out << "$"; + auto *TPO = cast(ND); + mangleTemplateArgValue(TPO->getType().getUnqualifiedType(), + TPO->getValue()); } else { mangle(ND, TA.getParamTypeForDecl()->isReferenceType() ? "$E?" : "$1?"); } @@ -1544,6 +1592,168 @@ } } +void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T, + const APValue &V, + bool WithScalarType) { + switch (V.getKind()) { + case APValue::None: + case APValue::Indeterminate: + // FIXME: MSVC doesn't allow this, so we can't be sure how it should be + // mangled. + if (WithScalarType) + mangleType(T, SourceRange(), QMM_Escape); + Out << '@'; + return; + + case APValue::Int: + if (WithScalarType) + mangleType(T, SourceRange(), QMM_Escape); + Out << '0'; + mangleNumber(V.getInt()); + return; + + case APValue::Float: + if (WithScalarType) + mangleType(T, SourceRange(), QMM_Escape); + mangleFloat(V.getFloat()); + return; + + case APValue::LValue: { + if (WithScalarType) + mangleType(T, SourceRange(), QMM_Escape); + + APValue::LValueBase Base = V.getLValueBase(); + if (Base.isNull()) + Out << "0A@"; + else if (auto *VD = Base.dyn_cast()) + mangle(VD, T->isReferenceType() ? "E?" : "1?"); + else + break; + + // FIXME: MSVC doesn't support template arguments referring to subobjects + // yet (it either mangles such template arguments as null pointers or + // small integers or crashes). It's probably the intent to mangle the + // declaration followed by an offset, but that's not what actually happens. + // For now just bail. + if (!V.hasLValuePath() || !V.getLValuePath().empty() || + V.isLValueOnePastTheEnd()) + break; + + return; + } + + case APValue::MemberPointer: { + if (WithScalarType) + mangleType(T, SourceRange(), QMM_Escape); + + // FIXME: The below manglings don't include a conversion, so bail if there + // would be one. MSVC mangles the (possibly converted) value of the + // pointer-to-member object as if it were a struct, leading to collisions + // in some cases. + if (!V.getMemberPointerPath().empty()) + break; + + const CXXRecordDecl *RD = + T->castAs()->getMostRecentCXXRecordDecl(); + const ValueDecl *D = V.getMemberPointerDecl(); + if (T->isMemberDataPointerType()) + mangleMemberDataPointer(RD, D, ""); + else + mangleMemberFunctionPointer(RD, cast_or_null(D), ""); + return; + } + + case APValue::Struct: { + Out << '2'; + mangleType(T, SourceRange(), QMM_Escape); + const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); + assert(RD && "unexpected type for record value"); + + unsigned BaseIndex = 0; + for (const CXXBaseSpecifier &B : RD->bases()) + mangleTemplateArgValue(B.getType(), V.getStructBase(BaseIndex++)); + for (const FieldDecl *FD : RD->fields()) + if (!FD->isUnnamedBitfield()) + mangleTemplateArgValue(FD->getType(), + V.getStructField(FD->getFieldIndex())); + Out << '@'; + return; + } + + case APValue::Union: + Out << '2'; + mangleType(T, SourceRange(), QMM_Escape); + // FIXME: MSVC doesn't mangle the active member, only the type, leading to + // collisions if more than one member has the same type. + // FIXME: MSVC doesn't yet support unions with no active member, but + // there's an obvious mangling for that, so we use it. + if (const FieldDecl *FD = V.getUnionField()) + mangleTemplateArgValue(FD->getType(), V.getUnionValue()); + Out << '@'; + return; + + case APValue::ComplexInt: + // We mangle complex types as structs, so mangle the value as a struct too. + Out << '2'; + mangleType(T, SourceRange(), QMM_Escape); + Out << '0'; + mangleNumber(V.getComplexIntReal()); + Out << '0'; + mangleNumber(V.getComplexIntImag()); + Out << '@'; + return; + + case APValue::ComplexFloat: + Out << '2'; + mangleType(T, SourceRange(), QMM_Escape); + mangleFloat(V.getComplexFloatReal()); + mangleFloat(V.getComplexFloatImag()); + Out << '@'; + return; + + case APValue::Array: { + Out << '3'; + QualType ElemT = getASTContext().getAsArrayType(T)->getElementType(); + mangleType(ElemT, SourceRange(), QMM_Escape); + for (unsigned I = 0, N = V.getArraySize(); I != N; ++I) { + const APValue &ElemV = I < V.getArrayInitializedElts() + ? V.getArrayInitializedElt(I) + : V.getArrayFiller(); + mangleTemplateArgValue(ElemT, ElemV, /*WithType*/false); + Out << '@'; + } + Out << '@'; + return; + } + + case APValue::Vector: { + // __m128 is mangled as a struct containing an array. We follow this + // approach for all vector types. + Out << '2'; + mangleType(T, SourceRange(), QMM_Escape); + Out << '3'; + QualType ElemT = T->castAs()->getElementType(); + mangleType(ElemT, SourceRange(), QMM_Escape); + for (unsigned I = 0, N = V.getVectorLength(); I != N; ++I) { + const APValue &ElemV = V.getVectorElt(I); + mangleTemplateArgValue(ElemT, ElemV, /*WithType*/false); + Out << '@'; + } + Out << "@@"; + return; + } + + case APValue::AddrLabelDiff: + case APValue::FixedPoint: + break; + } + + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, "cannot mangle this template argument yet"); + Diags.Report(DiagID); +} + void MicrosoftCXXNameMangler::mangleObjCProtocol(const ObjCProtocolDecl *PD) { llvm::SmallString<64> TemplateMangling; llvm::raw_svector_ostream Stream(TemplateMangling); diff --git a/clang/test/CodeGenCXX/mangle-class-nttp.cpp b/clang/test/CodeGenCXX/mangle-class-nttp.cpp --- a/clang/test/CodeGenCXX/mangle-class-nttp.cpp +++ b/clang/test/CodeGenCXX/mangle-class-nttp.cpp @@ -1,75 +1,111 @@ // RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-windows -emit-llvm -o - | FileCheck %s --check-prefix=MSABI #define fold(x) (__builtin_constant_p(x) ? (x) : (x)) -struct A { int a, b; }; +struct A { int a; const int b; }; template void f() {} // CHECK: define weak_odr void @_Z1fIXtl1ALi1ELi2EEEEvv( +// MSABI: define {{.*}} @"??$f@$2UA@@H00$$CBH01@@@YAXXZ" template void f(); -struct B { int *p; int k; }; +struct B { const int *p; int k; }; template void f() {} int n = 0; // CHECK: define weak_odr void @_Z1fIXtl1BadL_Z1nEEEEvv( +// MSABI: define {{.*}} @"??$f@$2UB@@PEBH1?n@@3HAH0A@@@@YAXXZ" template void f(); -// CHECK: define weak_odr void @_Z1fIXtl1BLPi0ELi1EEEEvv( +// CHECK: define weak_odr void @_Z1fIXtl1BLPKi0ELi1EEEEvv( +// MSABI: define {{.*}} @"??$f@$2UB@@PEBH0A@H00@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl1BEEEvv( +// MSABI: define {{.*}} @"??$f@$2UB@@PEBH0A@H0A@@@@YAXXZ" template void f(); -// CHECK: define weak_odr void @_Z1fIXtl1BLPi32EEEEvv( +#ifndef _WIN32 +// FIXME: MSVC crashes on the first of these and mangles the second the same as +// the nullptr version. Check the output is correct once we have a reference to +// compare against. +// CHECK: define weak_odr void @_Z1fIXtl1BLPKi32EEEEvv( template void f(); -// CHECK: define weak_odr void @_Z1fIXtl1BrcPiLi0EEEEEvv( +// CHECK: define weak_odr void @_Z1fIXtl1BrcPKiLi0EEEEvv( template void f(0))}>(); +#endif // Pointers to subobjects. struct Nested { union { int k; int arr[2]; }; } nested[2]; -struct Derived : A, Nested {} derived; -// CHECK: define weak_odr void @_Z1fIXtl1BadsoiL_Z6nestedE_EEEEvv +struct Derived : A, Nested { int z; } extern derived; +#ifndef _WIN32 +// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z6nestedE_EEEEvv +// FIXME: MSVC generates the garbage mangling ??$f@$2UB@@PEAH0A@H0A@@@@YAXXZ +// for this. template void f(); -// CHECK: define weak_odr void @_Z1fIXtl1BadsoiL_Z6nestedE16_0pEEEEvv +// FIXME: MSVC crashes on these. +// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z6nestedE16_0pEEEEvv template void f(); -// CHECK: define weak_odr void @_Z1fIXtl1BadsoiL_Z7derivedE8pEEEEvv +// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z7derivedE8pEEEEvv template void f(); -// CHECK: define weak_odr void @_Z1fIXtl1BcvPiplcvPcadL_Z7derivedELl16EEEEvv +// CHECK: define weak_odr void @_Z1fIXtl1BcvPKiplcvPcadL_Z7derivedELl16EEEEvv template void f(); +#endif // References to subobjects. -struct BR { int &r; }; +struct BR { const int &r; }; template
void f() {} -// CHECK: define weak_odr void @_Z1fIXtl2BRsoiL_Z6nestedE_EEEEvv +#ifndef _WIN32 +// FIXME: MSVC produces garbage manglings for these. +// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z6nestedE_EEEEvv template void f(); -// CHECK: define weak_odr void @_Z1fIXtl2BRsoiL_Z6nestedE12_0EEEEvv +// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z6nestedE12_0EEEEvv template void f(); -// CHECK: define weak_odr void @_Z1fIXtl2BRsoiL_Z7derivedE4EEEEvv +// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z7derivedE4EEEEvv template void f(); -// CHECK: define weak_odr void @_Z1fIXtl2BRdecvPiplcvPcadL_Z7derivedELl16EEEEvv +// FIXME: Crashes MSVC. +// CHECK: define weak_odr void @_Z1fIXtl2BRdecvPKiplcvPcadL_Z7derivedELl16EEEEvv template void f(); +#endif // Qualification conversions. struct C { const int *p; }; template void f() {} +#ifndef _WIN32 +// FIXME: MSVC produces a garbage mangling for this. // CHECK: define weak_odr void @_Z1fIXtl1CadsoKiL_Z7derivedE4EEEEvv template void f(); +#endif // Pointers to members. struct D { const int Derived::*p; int k; }; template void f() {} // CHECK: define weak_odr void @_Z1fIXtl1DLM7DerivedKi0ELi1EEEEvv +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0?0H00@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl1DEEEvv +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0?0H0A@@@@YAXXZ" template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1DadL_ZN7Derived1zEEEEEvv +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0BA@H0A@@@@YAXXZ" +template void f(); +#ifndef _WIN32 // CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN1A1aEEEEEEvv +// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0A@H0A@@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN1A1bEEEEEEvv +// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H03H0A@@@@YAXXZ" template void f(); // FIXME: Is the Ut_1 mangling here correct? -// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN6NestedUt_1kEE8EEEEvv -template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN6NestedUt_1kEE8ELi2EEEEvv +// FIXME: This mangles the same as &A::a (bug in the MS ABI). +// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0A@H01@@@YAXXZ" +template void f(); struct MoreDerived : A, Derived { int z; }; // CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN11MoreDerived1zEEn8EEEEvv +// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0BI@H0A@@@@YAXXZ" template void f(); +#endif + +// FIXME: Pointers to member functions. union E { int n; @@ -82,20 +118,47 @@ // Union members. // CHECK: define weak_odr void @_Z1fIXL1EEEEvv( +// FIXME: MSVC rejects this; check this is the mangling MSVC uses when they +// start accepting. +// MSABI: define {{.*}} @"??$f@$2TE@@@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl1EEEEvv( +// MSABI: define {{.*}} @"??$f@$2TE@@H0A@@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl1Edi1nLi42EEEEvv( +// MSABI: define {{.*}} @"??$f@$2TE@@H0CK@@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl1Edi1fLf00000000EEEEvv( +// MSABI: define {{.*}} @"??$f@$2TE@@MAA@@@@YAXXZ" template void f(); +// immintrin.h vector types. +typedef float __m128 __attribute__((__vector_size__(16))); +typedef double __m128d __attribute__((__vector_size__(16))); +typedef long long __m128i __attribute__((__vector_size__(16))); +struct M128 { __m128 a; }; +struct M128D { __m128d b; }; +struct M128I { __m128i c; }; +template void f() {} +template void f() {} +template void f() {} +// MSABI: define {{.*}} @"??$f@$2UM128@@2T__m128@@3MADPIAAAAA@@AEAAAAAAA@@AEAEAAAAA@@AEAIAAAAA@@@@@@@YAXXZ" +template void f(); +// MSABI: define {{.*}} @"??$f@$2UM128D@@2U__m128d@@3NBDPPAAAAAAAAAAAAA@@BEAAAAAAAAAAAAAAA@@@@@@@YAXXZ" +template void f(); +// FIXME: We define __m128i as a vector of long long, whereas MSVC appears to +// mangle it as if it were a vector of char. +// MSABI-FIXME: define {{.*}} @"??$f@$2UM128I@@2T__m128i@@3D00@01@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@@@@@@YAXXZ" +// MSABI: define {{.*}} @"??$f@$2UM128I@@2T__m128i@@3_J00@01@@@@@@YAXXZ" +template void f(); + // Extensions, and dropping trailing zero-initialized elements of 'tl' // manglings. typedef int __attribute__((ext_vector_type(3))) VI3; struct F { VI3 v; _Complex int ci; _Complex float cf; }; template void f() {} // CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEtlCiLi4ELi5EEtlCfLf40c00000ELf40e00000EEEEEvv +// MSABI: define {{.*}} @"??$f@$2UF@@2T?$__vector@H$02@__clang@@3H00@01@02@@@2U?$_Complex@H@3@0304@2U?$_Complex@M@3@AEAMAAAAA@AEAOAAAAA@@@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1ELi2ELi3EEtlCiLi4ELi5EEtlCfLf40c00000EEEEEvv template void f(); @@ -110,4 +173,171 @@ // CHECK: define weak_odr void @_Z1fIXtl1FtlDv3_iLi1EEEEEvv template void f(); // CHECK: define weak_odr void @_Z1fIXtl1FEEEvv +// MSABI: define {{.*}} @"??$f@$2UF@@2T?$__vector@H$02@__clang@@3H0A@@0A@@0A@@@@2U?$_Complex@H@3@0A@0A@@2U?$_Complex@M@3@AA@AA@@@@@YAXXZ" template void f(); + +// Unnamed bit-fields. +struct G { + int : 3; + int a : 4; + int : 5; + int b : 6; + int : 7; +}; +template void f() {} +// CHECK: define weak_odr void @_Z1fIXtl1GEEEvv +// MSABI: define {{.*}} @"??$f@$2UG@@H0A@H0A@@@@YAXXZ" +template void f<(G())>(); +// CHECK: define weak_odr void @_Z1fIXtl1GLi1EEEEvv +// MSABI: define {{.*}} @"??$f@$2UG@@H00H0A@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1GLi1ELi2EEEEvv +// MSABI: define {{.*}} @"??$f@$2UG@@H00H01@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1GLin8ELin32EEEEvv +// MSABI: define {{.*}} @"??$f@$2UG@@H0?7H0?CA@@@@YAXXZ" +template void f(); + +// Empty and nearly-empty unions. +// Some of the MSVC manglings here are our invention, because MSVC rejects, but +// seem likely to be right. +union H1 {}; +union H2 { int : 1, : 2, : 3; }; +union H3 { int : 1, a, : 2, b, : 3; }; +struct H4 { H2 h2; }; +template

void f() {} +template

void f() {} +template

void f() {} +template

void f() {} +// CHECK: define weak_odr void @_Z1fIXL2H1EEEvv +// MSABI: define {{.*}} @"??$f@$2TH1@@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXL2H2EEEvv +// MSABI: define {{.*}} @"??$f@$2TH2@@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2H3EEEvv +// MSABI: define {{.*}} @"??$f@$2TH3@@H0A@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2H3di1aLi1EEEEvv +// MSABI: define {{.*}} @"??$f@$2TH3@@H00@@@YAXXZ" +template void f(); +// FIXME: Leads to mangling collision under MS ABI; same mangling as the {.a = 0} case. +#ifndef _WIN32 +// CHECK: define weak_odr void @_Z1fIXtl2H3di1bLi0EEEEvv +template void f(); +#endif +// CHECK: define weak_odr void @_Z1fIXtl2H4EEEvv +// MSABI: define {{.*}} @"??$f@$2UH4@@2TH2@@@@@@YAXXZ" +template void f(); + +// Floating-point. +struct I { + float f; + double d; + long double ld; +}; +template void f() {} +// CHECK: define weak_odr void @_Z1fIXtl1IEEEvv +// MSABI: define {{.*}} @"??$f@$2UI@@MAA@NBA@OBA@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1ILf80000000ELd8000000000000000ELe80000000000000000000EEEEvv +// MSABI: define {{.*}} @"??$f@$2UI@@MAIAAAAAAA@NBIAAAAAAAAAAAAAAA@OBIAAAAAAAAAAAAAAA@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1ILf3f800000ELd4000000000000000ELec000c000000000000000EEEEvv +// MSABI: define {{.*}} @"??$f@$2UI@@MADPIAAAAA@NBEAAAAAAAAAAAAAAA@OBMAAIAAAAAAAAAAAA@@@@YAXXZ" +template void f(); +// CHECK: define {{.*}} @_Z1fIXtl1ILf00000000ELd0000000000000000ELe3bcd8000000000000000EEEEvv +// Note that "small integer" special-case manglings 'A@', '0', '1', ... are +// used here and represent tiny denormal values! +// MSABI: define {{.*}} @"??$f@$2UI@@MAA@NBA@OB0@@@YAXXZ" +template void f(); +// CHECK: define {{.*}} @_Z1fIXtl1ILf00000000ELd0000000000000002ELebbce8000000000000000EEEEvv +// ... but the special-case '?' mangling for bit 63 being set is not used. +// MSABI: define {{.*}} @"??$f@$2UI@@MAA@NB1OBIAAAAAAAAAAAAAAC@@@@YAXXZ" +template void f(); + +// Base classes and members of class type. +struct J1 { int a, b; }; +struct JEmpty {}; +struct J2 { int c, d; }; +struct J : J1, JEmpty, J2 { int e; }; +template void f() {} +// CHECK: define weak_odr void @_Z1fIXtl1JEEEvv +// MSABI: define {{.*}} @"??$f@$2UJ@@2UJ1@@H0A@H0A@@2UJEmpty@@@2UJ2@@H0A@H0A@@H0A@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl1Jtl2J1Li1ELi2EEtl6JEmptyEtl2J2Li3ELi4EELi5EEEEvv +// MSABI: define {{.*}} @"??$f@$2UJ@@2UJ1@@H00H01@2UJEmpty@@@2UJ2@@H02H03@H04@@@YAXXZ" +template void f(); + +struct J3 { J1 j1; }; +template void f() {} +// CHECK: define {{.*}} @_Z1fIXtl2J3tl2J1Li1ELi2EEEEEvv +// MSABI: define {{.*}} @"??$f@$2UJ3@@2UJ1@@H00H01@@@@YAXXZ" +template void f(); + +// Arrays. +struct K { int n[2][3]; }; +template void f() {} +// CHECK: define {{.*}} @_Z1fIXtl1KtlA2_A3_itlS1_Li1ELi2EEEEEEvv +// MSABI: define {{.*}} @"??$f@$2UK@@3$$BY02H3H00@01@0A@@@@3H0A@@0A@@0A@@@@@@@@YAXXZ" +template void f(); +// CHECK: define {{.*}} @_Z1fIXtl1KtlA2_A3_itlS1_Li1ELi2ELi3EEtlS1_Li4ELi5ELi6EEEEEEvv +// MSABI: define {{.*}} @"??$f@$2UK@@3$$BY02H3H00@01@02@@@3H03@04@05@@@@@@@YAXXZ" +template void f(); + +struct K1 { int a, b; }; +struct K2 : K1 { int c; }; +struct K3 { K2 k2[2]; }; +template void f() {} +// CHECK: define {{.*}} @_Z1fIXtl2K3tlA2_2K2tlS1_tl2K1Li1EEEEEEEvv +// MSABI: define {{.*}} @"??$f@$2UK3@@3UK2@@2U2@2UK1@@H00H0A@@H0A@@@2U2@2U3@H0A@H0A@@H0A@@@@@@@YAXXZ" +template void f(); +template void f(); + +namespace CvQualifiers { + struct A { const int a; int *const b; int c; }; + template void f() {} + // CHECK: define {{.*}} @_ZN12CvQualifiers1fIXtlNS_1AELi0ELPi0ELi1EEEEEvv + // MSABI: define {{.*}} @"??$f@$2UA@CvQualifiers@@$$CBH0A@QEAH0A@H00@@CvQualifiers@@YAXXZ" + template void f(); + + using T1 = const int; + using T2 = T1[5]; + using T3 = const T2; + struct B { T3 arr; }; + template void f() {} + // CHECK: define {{.*}} @_ZN12CvQualifiers1fIXtlNS_1BEtlA5_iLi1ELi2ELi3ELi4ELi5EEEEEEvv + // MSABI: define {{.*}} @"??$f@$2UB@CvQualifiers@@3$$CBH00@01@02@03@04@@@@CvQualifiers@@YAXXZ" + template void f(); +} + +struct L { + signed char a = -1; + unsigned char b = -1; + short c = -1; + unsigned short d = -1; + int e = -1; + unsigned int f = -1; + long g = -1; + unsigned long h = -1; + long long i = -1; + unsigned long long j = -1; +}; +template void f() {} +// CHECK: define {{.*}} @_Z1fIXtl1LLan1ELh255ELsn1ELt65535ELin1ELj4294967295ELln1ELm18446744073709551615ELxn1ELy18446744073709551615EEEEvv +// MSABI: define {{.*}} @"??$f@$2UL@@C0?0E0PP@F0?0G0PPPP@H0?0I0PPPPPPPP@J0?0K0PPPPPPPP@_J0?0_K0?0@@@YAXXZ" +template void f(); + +// Template parameter objects. +struct M { int n; }; +template constexpr const M &f() { return a; } +// CHECK: define {{.*}} @_Z1fIXtl1MLi42EEEERKS0_v +// CHECK: ret {{.*}} @_ZTAXtl1MLi42EEE +// MSABI: define {{.*}} @"??$f@$2UM@@H0CK@@@@YAAEBUM@@XZ" +// MSABI: ret {{.*}} @"??__N2UM@@H0CK@@@" +template const M &f(); + +template void g() {} +// CHECK: define {{.*}} @_Z1gIXadL_ZTAXtl1MLi10EEEEEEvv +// MSABI: define {{.*}} @"??$g@$1??__N2UM@@H09@@@@YAXXZ" +template void g<&f()>(); diff --git a/clang/test/CodeGenCXX/mangle-ms-templates.cpp b/clang/test/CodeGenCXX/mangle-ms-templates.cpp --- a/clang/test/CodeGenCXX/mangle-ms-templates.cpp +++ b/clang/test/CodeGenCXX/mangle-ms-templates.cpp @@ -310,3 +310,20 @@ template struct UUIDType4<&__uuidof(uuid)>; // CHECK: "?bar@?$UUIDType4@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@QAEXXZ" // CHECK: "?foo@?$UUIDType3@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@QAEXXZ" + +#ifdef _WIN64 +template<__int128 N> struct Int128 {}; +template struct UInt128 {}; +// X64: define {{.*}} @"?fun_int128@@YAXU?$Int128@$0A@@@@Z"( +void fun_int128(Int128<0>) {} +// X64: define {{.*}} @"?fun_int128@@YAXU?$Int128@$0?0@@@Z"( +void fun_int128(Int128<-1>) {} +// X64: define {{.*}} @"?fun_int128@@YAXU?$Int128@$0DPPPPPPPPPPPPPPPAAAAAAAAAAAAAAAB@@@@Z"( +void fun_int128(Int128<(__int128)9223372036854775807 * (__int128)9223372036854775807>) {} +// X64: define {{.*}} @"?fun_uint128@@YAXU?$UInt128@$0A@@@@Z"( +void fun_uint128(UInt128<0>) {} +// X64: define {{.*}} @"?fun_uint128@@YAXU?$UInt128@$0?0@@@Z"( +void fun_uint128(UInt128<(unsigned __int128)-1>) {} +// X64: define {{.*}} @"?fun_uint128@@YAXU?$UInt128@$0DPPPPPPPPPPPPPPPAAAAAAAAAAAAAAAB@@@@Z"( +void fun_uint128(UInt128<(unsigned __int128)9223372036854775807 * (unsigned __int128)9223372036854775807>) {} +#endif diff --git a/clang/test/CodeGenCXX/template-param-objects.cpp b/clang/test/CodeGenCXX/template-param-objects.cpp --- a/clang/test/CodeGenCXX/template-param-objects.cpp +++ b/clang/test/CodeGenCXX/template-param-objects.cpp @@ -1,12 +1,19 @@ -// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 %s -emit-llvm -o - | FileCheck %s --check-prefixes=ITANIUM,CHECK +// RUN: %clang_cc1 -triple x86_64-windows -std=c++20 %s -emit-llvm -o - | FileCheck %s --check-prefixes=MSABI,CHECK struct S { char buf[32]; }; template constexpr const char *begin() { return s.buf; } template constexpr const char *end() { return s.buf + __builtin_strlen(s.buf); } -// CHECK: [[HELLO:@_ZTAXtl1StlA32_cLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100EEEE]] = linkonce_odr constant { <{ [11 x i8], [21 x i8] }> } { <{ [11 x i8], [21 x i8] }> <{ [11 x i8] c"hello world", [21 x i8] zeroinitializer }> }, comdat +// ITANIUM: [[HELLO:@_ZTAXtl1StlA32_cLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100EEEE]] +// MSABI: [[HELLO:@"[?][?]__N2US@@3D0GI@@0GF@@0GM@@0GM@@0GP@@0CA@@0HH@@0GP@@0HC@@0GM@@0GE@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@0A@@@@@"]] +// CHECK-SAME: = linkonce_odr constant { <{ [11 x i8], [21 x i8] }> } { <{ [11 x i8], [21 x i8] }> <{ [11 x i8] c"hello world", [21 x i8] zeroinitializer }> }, comdat -// CHECK: @p = global i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0) +// ITANIUM: @p +// MSABI: @"?p@@3PEBDEB" +// CHECK-SAME: global i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0) const char *p = begin(); -// CHECK: @q = global i8* getelementptr (i8, i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0), i64 11) +// ITANIUM: @q +// MSABI: @"?q@@3PEBDEB" +// CHECK-SAME: global i8* getelementptr (i8, i8* getelementptr inbounds ({{.*}}* [[HELLO]], i32 0, i32 0, i32 0, i32 0), i64 11) const char *q = end();