diff options
-rw-r--r-- | clang/include/clang/AST/ASTContext.h | 4 | ||||
-rw-r--r-- | clang/include/clang/AST/Mangle.h | 9 | ||||
-rw-r--r-- | clang/include/clang/AST/MangleNumberingContext.h | 9 | ||||
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 14 | ||||
-rw-r--r-- | clang/include/clang/Sema/Scope.h | 35 | ||||
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 11 | ||||
-rw-r--r-- | clang/lib/AST/ItaniumCXXABI.cpp | 7 | ||||
-rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 33 | ||||
-rw-r--r-- | clang/lib/AST/MangleNumberingContext.cpp | 6 | ||||
-rw-r--r-- | clang/lib/AST/MicrosoftCXXABI.cpp | 12 | ||||
-rw-r--r-- | clang/lib/AST/MicrosoftMangle.cpp | 282 | ||||
-rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Parse/ParseStmt.cpp | 28 | ||||
-rw-r--r-- | clang/lib/Sema/Scope.cpp | 95 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 25 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 1 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/mangle-ms-abi-examples.cpp | 6 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp | 8 |
18 files changed, 385 insertions, 202 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 6ed7c0804b1..20fddf2d44a 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -365,6 +365,7 @@ private: /// \brief Side-table of mangling numbers for declarations which rarely /// need them (like static local vars). llvm::DenseMap<const NamedDecl *, unsigned> MangleNumbers; + llvm::DenseMap<const VarDecl *, unsigned> StaticLocalNumbers; /// \brief Mapping that stores parameterIndex values for ParmVarDecls when /// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex. @@ -2171,6 +2172,9 @@ public: void setManglingNumber(const NamedDecl *ND, unsigned Number); unsigned getManglingNumber(const NamedDecl *ND) const; + void setStaticLocalNumber(const VarDecl *VD, unsigned Number); + unsigned getStaticLocalNumber(const VarDecl *VD) const; + /// \brief Retrieve the context for computing mangling numbers in the given /// DeclContext. MangleNumberingContext &getManglingNumberContext(const DeclContext *DC); diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h index d1145b17a93..6281716c962 100644 --- a/clang/include/clang/AST/Mangle.h +++ b/clang/include/clang/AST/Mangle.h @@ -80,6 +80,7 @@ private: llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds; llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds; + llvm::DenseMap<const TagDecl*, uint64_t> AnonStructIds; public: ManglerKind getKind() const { return Kind; } @@ -104,7 +105,13 @@ public: Result = BlockIds.insert(std::make_pair(BD, BlockIds.size())); return Result.first->second; } - + + uint64_t getAnonymousStructId(const TagDecl *TD) { + std::pair<llvm::DenseMap<const TagDecl *, uint64_t>::iterator, bool> + Result = AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size())); + return Result.first->second; + } + /// @name Mangler Entry Points /// @{ diff --git a/clang/include/clang/AST/MangleNumberingContext.h b/clang/include/clang/AST/MangleNumberingContext.h index 5a227f201fb..adf2b308180 100644 --- a/clang/include/clang/AST/MangleNumberingContext.h +++ b/clang/include/clang/AST/MangleNumberingContext.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_MANGLENUMBERINGCONTEXT_H #include "clang/Basic/LLVM.h" +#include "clang/Sema/Scope.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" @@ -33,7 +34,6 @@ class VarDecl; class MangleNumberingContext : public RefCountedBase<MangleNumberingContext> { llvm::DenseMap<const Type *, unsigned> ManglingNumbers; - llvm::DenseMap<IdentifierInfo*, unsigned> TagManglingNumbers; public: virtual ~MangleNumberingContext() {} @@ -46,13 +46,16 @@ public: /// context. unsigned getManglingNumber(const BlockDecl *BD); + /// Static locals are numbered by source order. + unsigned getStaticLocalNumber(const VarDecl *VD); + /// \brief Retrieve the mangling number of a static local variable within /// this context. - virtual unsigned getManglingNumber(const VarDecl *VD) = 0; + virtual unsigned getManglingNumber(const VarDecl *VD, Scope *S) = 0; /// \brief Retrieve the mangling number of a static local variable within /// this context. - unsigned getManglingNumber(const TagDecl *TD); + virtual unsigned getManglingNumber(const TagDecl *TD, Scope *S) = 0; }; } // end namespace clang diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index ddb22f51281..e452ecff131 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -737,14 +737,18 @@ public: public: // ParseScope - Construct a new object to manage a scope in the // parser Self where the new Scope is created with the flags - // ScopeFlags, but only when ManageScope is true (the default). If - // ManageScope is false, this object does nothing. - ParseScope(Parser *Self, unsigned ScopeFlags, bool ManageScope = true) + // ScopeFlags, but only when we aren't about to enter a compound statement. + ParseScope(Parser *Self, unsigned ScopeFlags, bool EnteredScope = true, + bool BeforeCompoundStmt = false) : Self(Self) { - if (ManageScope) + if (EnteredScope && !BeforeCompoundStmt) Self->EnterScope(ScopeFlags); - else + else { + if (BeforeCompoundStmt) + Self->getCurScope()->incrementMSLocalManglingNumber(); + this->Self = 0; + } } // Exit - Exit the scope associated with this object now, rather diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h index 7e15fdeafdf..21e5cde3f7a 100644 --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -18,6 +18,12 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" +namespace llvm { + +class raw_ostream; + +} + namespace clang { class Decl; @@ -109,6 +115,10 @@ private: /// interrelates with other control flow statements. unsigned short Flags; + /// \brief Declarations with static linkage are mangled with the number of + /// scopes seen as a component. + unsigned short MSLocalManglingNumber; + /// PrototypeDepth - This is the number of function prototype scopes /// enclosing this scope, including this scope. unsigned short PrototypeDepth; @@ -120,6 +130,7 @@ private: /// FnParent - If this scope has a parent scope that is a function body, this /// pointer is non-null and points to it. This is used for label processing. Scope *FnParent; + Scope *MSLocalManglingParent; /// BreakParent/ContinueParent - This is a direct link to the innermost /// BreakScope/ContinueScope which contains the contents of this scope @@ -181,6 +192,11 @@ public: const Scope *getFnParent() const { return FnParent; } Scope *getFnParent() { return FnParent; } + const Scope *getMSLocalManglingParent() const { + return MSLocalManglingParent; + } + Scope *getMSLocalManglingParent() { return MSLocalManglingParent; } + /// getContinueParent - Return the closest scope that a continue statement /// would be affected by. Scope *getContinueParent() { @@ -232,6 +248,22 @@ public: DeclsInScope.erase(D); } + void incrementMSLocalManglingNumber() { + if (Scope *MSLMP = getMSLocalManglingParent()) + MSLMP->MSLocalManglingNumber += 1; + } + + void decrementMSLocalManglingNumber() { + if (Scope *MSLMP = getMSLocalManglingParent()) + MSLMP->MSLocalManglingNumber -= 1; + } + + unsigned getMSLocalManglingNumber() const { + if (const Scope *MSLMP = getMSLocalManglingParent()) + return MSLMP->MSLocalManglingNumber; + return 1; + } + /// isDeclScope - Return true if this is the scope that the specified decl is /// declared in. bool isDeclScope(Decl *D) { @@ -359,6 +391,9 @@ public: /// variables accordingly. /// void AddFlags(unsigned Flags); + + void dumpImpl(raw_ostream &OS) const; + void dump() const; }; } // end namespace clang diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 545228a1787..b1f31c429ed 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -8052,6 +8052,17 @@ unsigned ASTContext::getManglingNumber(const NamedDecl *ND) const { return I != MangleNumbers.end() ? I->second : 1; } +void ASTContext::setStaticLocalNumber(const VarDecl *VD, unsigned Number) { + if (Number > 1) + StaticLocalNumbers[VD] = Number; +} + +unsigned ASTContext::getStaticLocalNumber(const VarDecl *VD) const { + llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = + StaticLocalNumbers.find(VD); + return I != StaticLocalNumbers.end() ? I->second : 1; +} + MangleNumberingContext & ASTContext::getManglingNumberContext(const DeclContext *DC) { assert(LangOpts.CPlusPlus); // We don't need mangling numbers for plain C. diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp index 8928e66724e..f0d20c36968 100644 --- a/clang/lib/AST/ItaniumCXXABI.cpp +++ b/clang/lib/AST/ItaniumCXXABI.cpp @@ -33,12 +33,17 @@ namespace { /// literals within a particular context. class ItaniumNumberingContext : public MangleNumberingContext { llvm::DenseMap<IdentifierInfo*, unsigned> VarManglingNumbers; + llvm::DenseMap<IdentifierInfo*, unsigned> TagManglingNumbers; public: /// Variable decls are numbered by identifier. - virtual unsigned getManglingNumber(const VarDecl *VD) { + virtual unsigned getManglingNumber(const VarDecl *VD, Scope *) { return ++VarManglingNumbers[VD->getIdentifier()]; } + + virtual unsigned getManglingNumber(const TagDecl *TD, Scope *) { + return ++TagManglingNumbers[TD->getIdentifier()]; + } }; class ItaniumCXXABI : public CXXABI { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 074b950ce9e..61fc4a308ea 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -101,11 +101,18 @@ static const NamedDecl *getStructor(const NamedDecl *decl) { const FunctionDecl *fn = dyn_cast_or_null<FunctionDecl>(decl); return (fn ? getStructor(fn) : decl); } - + +static bool isLambda(const NamedDecl *ND) { + const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(ND); + if (!Record) + return false; + + return Record->isLambda(); +} + static const unsigned UnknownArity = ~0U; class ItaniumMangleContextImpl : public ItaniumMangleContext { - llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds; typedef std::pair<const DeclContext*, IdentifierInfo*> DiscriminatorKeyTy; llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator; llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier; @@ -115,13 +122,6 @@ public: DiagnosticsEngine &Diags) : ItaniumMangleContext(Context, Diags) {} - uint64_t getAnonymousStructId(const TagDecl *TD) { - std::pair<llvm::DenseMap<const TagDecl *, - uint64_t>::iterator, bool> Result = - AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size())); - return Result.first->second; - } - /// @name Mangler Entry Points /// @{ @@ -158,9 +158,8 @@ public: bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { // Lambda closure types are already numbered. - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND)) - if (RD->isLambda()) - return false; + if (isLambda(ND)) + return false; // Anonymous tags are already numbered. if (const TagDecl *Tag = dyn_cast<TagDecl>(ND)) { @@ -538,14 +537,6 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { return 0; } -static bool isLambda(const NamedDecl *ND) { - const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(ND); - if (!Record) - return false; - - return Record->isLambda(); -} - void CXXNameMangler::mangleName(const NamedDecl *ND) { // <name> ::= <nested-name> // ::= <unscoped-name> @@ -1149,7 +1140,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, } // Get a unique id for the anonymous struct. - uint64_t AnonStructId = Context.getAnonymousStructId(TD); + unsigned AnonStructId = Context.getAnonymousStructId(TD); // Mangle it as a source name in the form // [n] $_<id> diff --git a/clang/lib/AST/MangleNumberingContext.cpp b/clang/lib/AST/MangleNumberingContext.cpp index ec503e01932..b46a085dc9e 100644 --- a/clang/lib/AST/MangleNumberingContext.cpp +++ b/clang/lib/AST/MangleNumberingContext.cpp @@ -38,6 +38,8 @@ MangleNumberingContext::getManglingNumber(const BlockDecl *BD) { } unsigned -MangleNumberingContext::getManglingNumber(const TagDecl *TD) { - return ++TagManglingNumbers[TD->getIdentifier()]; +MangleNumberingContext::getStaticLocalNumber(const VarDecl *VD) { + // FIXME: Compute a BlockPointerType? Not obvious how. + const Type *Ty = 0; + return ++ManglingNumbers[Ty]; } diff --git a/clang/lib/AST/MicrosoftCXXABI.cpp b/clang/lib/AST/MicrosoftCXXABI.cpp index 6d015c3b479..f2fd848d264 100644 --- a/clang/lib/AST/MicrosoftCXXABI.cpp +++ b/clang/lib/AST/MicrosoftCXXABI.cpp @@ -28,15 +28,13 @@ namespace { /// \brief Numbers things which need to correspond across multiple TUs. /// Typically these are things like static locals, lambdas, or blocks. class MicrosoftNumberingContext : public MangleNumberingContext { - unsigned NumStaticLocals; - public: - MicrosoftNumberingContext() : NumStaticLocals(0) { } + virtual unsigned getManglingNumber(const VarDecl *VD, Scope *S) { + return S->getMSLocalManglingNumber(); + } - /// Static locals are numbered by source order. - virtual unsigned getManglingNumber(const VarDecl *VD) { - assert(VD->isStaticLocal()); - return ++NumStaticLocals; + virtual unsigned getManglingNumber(const TagDecl *TD, Scope *S) { + return S->getMSLocalManglingNumber(); } }; diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index a610e157d90..24bd2a5a365 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -25,6 +25,7 @@ #include "clang/Basic/ABI.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" using namespace clang; @@ -72,10 +73,89 @@ static const FunctionDecl *getStructor(const FunctionDecl *fn) { return fn; } +static bool isLambda(const NamedDecl *ND) { + const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(ND); + if (!Record) + return false; + + return Record->isLambda(); +} + +/// MicrosoftMangleContextImpl - Overrides the default MangleContext for the +/// Microsoft Visual C++ ABI. +class MicrosoftMangleContextImpl : public MicrosoftMangleContext { + typedef std::pair<const DeclContext *, IdentifierInfo *> DiscriminatorKeyTy; + llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator; + llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier; + +public: + MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags) + : MicrosoftMangleContext(Context, Diags) {} + virtual bool shouldMangleCXXName(const NamedDecl *D); + virtual void mangleCXXName(const NamedDecl *D, raw_ostream &Out); + virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, + raw_ostream &); + virtual void mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + raw_ostream &); + virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + raw_ostream &); + virtual void mangleCXXVFTable(const CXXRecordDecl *Derived, + ArrayRef<const CXXRecordDecl *> BasePath, + raw_ostream &Out); + virtual void mangleCXXVBTable(const CXXRecordDecl *Derived, + ArrayRef<const CXXRecordDecl *> BasePath, + raw_ostream &Out); + virtual void mangleCXXRTTI(QualType T, raw_ostream &); + virtual void mangleCXXRTTIName(QualType T, raw_ostream &); + virtual void mangleTypeName(QualType T, raw_ostream &); + virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, + raw_ostream &); + virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, + raw_ostream &); + virtual void mangleReferenceTemporary(const VarDecl *, raw_ostream &); + virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out); + virtual void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out); + virtual void mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out); + bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { + // Lambda closure types are already numbered. + if (isLambda(ND)) + return false; + + const DeclContext *DC = getEffectiveDeclContext(ND); + if (!DC->isFunctionOrMethod()) + return false; + + // Use the canonical number for externally visible decls. + if (ND->isExternallyVisible()) { + disc = getASTContext().getManglingNumber(ND); + return true; + } + + // Anonymous tags are already numbered. + if (const TagDecl *Tag = dyn_cast<TagDecl>(ND)) { + if (Tag->getName().empty() && !Tag->getTypedefNameForAnonDecl()) + return false; + } + + // Make up a reasonable number for internal decls. + unsigned &discriminator = Uniquifier[ND]; + if (!discriminator) + discriminator = ++Discriminator[std::make_pair(DC, ND->getIdentifier())]; + disc = discriminator; + return true; + } + +private: + void mangleInitFiniStub(const VarDecl *D, raw_ostream &Out, char CharCode); +}; + /// MicrosoftCXXNameMangler - Manage the mangling of a single name for the /// Microsoft Visual C++ ABI. class MicrosoftCXXNameMangler { - MangleContext &Context; + MicrosoftMangleContextImpl &Context; raw_ostream &Out; /// The "structor" is the top-level declaration being mangled, if @@ -100,14 +180,14 @@ class MicrosoftCXXNameMangler { public: enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result }; - MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_) + MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_) : Context(C), Out(Out_), Structor(0), StructorType(-1), UseNameBackReferences(true), PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == 64) { } - MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_, + MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_, const CXXDestructorDecl *D, CXXDtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), @@ -133,7 +213,7 @@ public: QualifierMangleMode QMM = QMM_Mangle); void mangleFunctionType(const FunctionType *T, const FunctionDecl *D = 0, bool ForceInstMethod = false); - void manglePostfix(const DeclContext *DC, bool NoFunction = false); + void mangleNestedName(const NamedDecl *ND); private: void disableBackReferences() { UseNameBackReferences = false; } @@ -152,7 +232,6 @@ private: void mangleTemplateInstantiationName(const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs); void mangleObjCMethodName(const ObjCMethodDecl *MD); - void mangleLocalName(const FunctionDecl *FD); void mangleArgumentType(QualType T, SourceRange Range); @@ -179,46 +258,6 @@ private: const TemplateArgumentList &TemplateArgs); void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA); }; - -/// MicrosoftMangleContextImpl - Overrides the default MangleContext for the -/// Microsoft Visual C++ ABI. -class MicrosoftMangleContextImpl : public MicrosoftMangleContext { -public: - MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags) - : MicrosoftMangleContext(Context, Diags) {} - virtual bool shouldMangleCXXName(const NamedDecl *D); - virtual void mangleCXXName(const NamedDecl *D, raw_ostream &Out); - virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, - raw_ostream &); - virtual void mangleThunk(const CXXMethodDecl *MD, - const ThunkInfo &Thunk, - raw_ostream &); - virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, - const ThisAdjustment &ThisAdjustment, - raw_ostream &); - virtual void mangleCXXVFTable(const CXXRecordDecl *Derived, - ArrayRef<const CXXRecordDecl *> BasePath, - raw_ostream &Out); - virtual void mangleCXXVBTable(const CXXRecordDecl *Derived, - ArrayRef<const CXXRecordDecl *> BasePath, - raw_ostream &Out); - virtual void mangleCXXRTTI(QualType T, raw_ostream &); - virtual void mangleCXXRTTIName(QualType T, raw_ostream &); - virtual void mangleTypeName(QualType T, raw_ostream &); - virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, - raw_ostream &); - virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, - raw_ostream &); - virtual void mangleReferenceTemporary(const VarDecl *, raw_ostream &); - virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out); - virtual void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out); - virtual void mangleDynamicAtExitDestructor(const VarDecl *D, - raw_ostream &Out); - -private: - void mangleInitFiniStub(const VarDecl *D, raw_ostream &Out, char CharCode); -}; - } bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) { @@ -497,18 +536,11 @@ void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk( void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { // <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @ - const DeclContext *DC = ND->getDeclContext(); // Always start with the unqualified name. mangleUnqualifiedName(ND); - // If this is an extern variable declared locally, the relevant DeclContext - // is that of the containing namespace, or the translation unit. - if (isa<FunctionDecl>(DC) && ND->hasLinkage()) - while (!DC->isNamespace() && !DC->isTranslationUnit()) - DC = DC->getParent(); - - manglePostfix(DC); + mangleNestedName(ND); // Terminate the whole name with an '@'. Out << '@'; @@ -647,6 +679,20 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, } } + if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { + // We must have an anonymous union or struct declaration. + const CXXRecordDecl *RD = VD->getType()->getAsCXXRecordDecl(); + assert(RD && "expected variable decl to have a record type"); + // Anonymous types with no tag or typedef get the name of their + // declarator mangled in. If they have no declarator, number them with + // a $S prefix. + llvm::SmallString<64> Name("$S"); + // Get a unique id for the anonymous struct. + Name += llvm::utostr(Context.getAnonymousStructId(RD) + 1); + mangleSourceName(Name.str()); + break; + } + // We must have an anonymous struct. const TagDecl *TD = cast<TagDecl>(ND); if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) { @@ -658,18 +704,18 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, break; } + llvm::SmallString<64> Name("<unnamed-type-"); if (TD->hasDeclaratorForAnonDecl()) { // Anonymous types with no tag or typedef get the name of their - // declarator mangled in. - llvm::SmallString<64> Name("<unnamed-type-"); + // declarator mangled in if they have one. Name += TD->getDeclaratorForAnonDecl()->getName(); - Name += ">"; - mangleSourceName(Name.str()); } else { - // Anonymous types with no tag, no typedef, or declarator get - // '<unnamed-tag>'. - mangleSourceName("<unnamed-tag>"); + // Otherwise, number the types using a $S prefix. + Name += "$S"; + Name += llvm::utostr(Context.getAnonymousStructId(TD) + 1); } + Name += ">"; + mangleSourceName(Name.str()); break; } @@ -721,45 +767,44 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, } } -void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC, - bool NoFunction) { +void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) { // <postfix> ::= <unqualified-name> [<postfix>] // ::= <substitution> [<postfix>] + const DeclContext *DC = ND->getDeclContext(); - if (!DC) return; + while (!DC->isTranslationUnit()) { + if (isa<TagDecl>(ND) || isa<VarDecl>(ND)) { + unsigned Disc; + if (Context.getNextDiscriminator(ND, Disc)) { + Out << '?'; + mangleNumber(Disc); + Out << '?'; + } + } - while (isa<LinkageSpecDecl>(DC)) + if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) { + DiagnosticsEngine Diags = Context.getDiags(); + unsigned DiagID = + Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle a local inside this block yet"); + Diags.Report(BD->getLocation(), DiagID); + + // FIXME: This is completely, utterly, wrong; see ItaniumMangle + // for how this should be done. + Out << "__block_invoke" << Context.getBlockId(BD, false); + Out << '@'; + continue; + } else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) { + mangleObjCMethodName(Method); + } else if (isa<NamedDecl>(DC)) { + ND = cast<NamedDecl>(DC); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { + mangle(FD, "?"); + break; + } else + mangleUnqualifiedName(ND); + } DC = DC->getParent(); - - if (DC->isTranslationUnit()) - return; - - if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) { - DiagnosticsEngine Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle a local inside this block yet"); - Diags.Report(BD->getLocation(), DiagID); - - // FIXME: This is completely, utterly, wrong; see ItaniumMangle - // for how this should be done. - Out << "__block_invoke" << Context.getBlockId(BD, false); - Out << '@'; - return manglePostfix(DC->getParent(), NoFunction); - } else if (isa<CapturedDecl>(DC)) { - // Skip CapturedDecl context. - manglePostfix(DC->getParent(), NoFunction); - return; - } - - if (NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC))) - return; - else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) - mangleObjCMethodName(Method); - else if (const FunctionDecl *Func = dyn_cast<FunctionDecl>(DC)) - mangleLocalName(Func); - else { - mangleUnqualifiedName(cast<NamedDecl>(DC)); - manglePostfix(DC->getParent(), NoFunction); } } @@ -933,44 +978,6 @@ void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { Context.mangleObjCMethodName(MD, Out); } -// Find out how many function decls live above this one and return an integer -// suitable for use as the number in a numbered anonymous scope. -// TODO: Memoize. -static unsigned getLocalNestingLevel(const FunctionDecl *FD) { - const DeclContext *DC = FD->getParent(); - int level = 1; - - while (DC && !DC->isTranslationUnit()) { - if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) level++; - DC = DC->getParent(); - } - - return 2*level; -} - -void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) { - // <nested-name> ::= <numbered-anonymous-scope> ? <mangled-name> - // <numbered-anonymous-scope> ::= ? <number> - // Even though the name is rendered in reverse order (e.g. - // A::B::C is rendered as C@B@A), VC numbers the scopes from outermost to - // innermost. So a method bar in class C local to function foo gets mangled - // as something like: - // ?bar@C@?1??foo@@YAXXZ@QAEXXZ - // This is more apparent when you have a type nested inside a method of a - // type nested inside a function. A method baz in class D local to method - // bar of class C local to function foo gets mangled as: - // ?baz@D@?3??bar@C@?1??foo@@YAXXZ@QAEXXZ@QAEXXZ - // This scheme is general enough to support GCC-style nested - // functions. You could have a method baz of class C inside a function bar - // inside a function foo, like so: - // ?baz@C@?3??bar@?1??foo@@YAXXZ@YAXXZ@QAEXXZ - unsigned NestLevel = getLocalNestingLevel(FD); - Out << '?'; - mangleNumber(NestLevel); - Out << '?'; - mangle(FD, "?"); -} - void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs) { @@ -2228,7 +2235,7 @@ void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD, // N.B. This means that they can get more than 32 static variable guards in a // scope. It also means that they broke compatibility with their own ABI. - // <guard-name> ::= ?_B <postfix> @51 + // <guard-name> ::= ?_B <postfix> @5 <scope-depth> // ::= ?$S <guard-num> @ <postfix> @4IA // The first mangling is what MSVC uses to guard static locals in inline @@ -2242,8 +2249,13 @@ void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD, bool Visible = VD->isExternallyVisible(); // <operator-name> ::= ?_B # local static guard Mangler.getStream() << (Visible ? "\01??_B" : "\01?$S1@"); - Mangler.manglePostfix(VD->getDeclContext()); - Mangler.getStream() << (Visible ? "@51" : "@4IA"); + Mangler.mangleNestedName(VD); + Mangler.getStream() << (Visible ? "@5" : "@4IA"); + if (Visible) { + unsigned ScopeDepth; + getNextDiscriminator(VD, ScopeDepth); + Mangler.mangleNumber(ScopeDepth); + } } void MicrosoftMangleContextImpl::mangleInitFiniStub(const VarDecl *D, diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 12b743ab003..aac76e7334e 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1291,7 +1291,7 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, if (D.isExternallyVisible()) { // Externally visible variables have to be numbered in Sema to properly // handle unreachable VarDecls. - BitIndex = getContext().getManglingNumber(&D); + BitIndex = getContext().getStaticLocalNumber(&D); assert(BitIndex > 0); BitIndex--; } else { diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 87074cc09fb..4cd27fe88f5 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1078,8 +1078,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { // would have to notify ParseStatement not to create a new scope. It's // simpler to let it create a new scope. // - ParseScope InnerScope(this, Scope::DeclScope, - C99orCXX && Tok.isNot(tok::l_brace)); + ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); // Read the 'then' stmt. SourceLocation ThenStmtLoc = Tok.getLocation(); @@ -1111,8 +1110,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { // The substatement in a selection-statement (each substatement, in the else // form of the if statement) implicitly defines a local scope. // - ParseScope InnerScope(this, Scope::DeclScope, - C99orCXX && Tok.isNot(tok::l_brace)); + ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); ElseStmt = ParseStatement(); @@ -1215,8 +1213,7 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) { // condition and a new scope for substatement in C++. // getCurScope()->AddFlags(Scope::BreakScope); - ParseScope InnerScope(this, Scope::DeclScope, - C99orCXX && Tok.isNot(tok::l_brace)); + ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); // Read the body statement. StmtResult Body(ParseStatement(TrailingElseLoc)); @@ -1293,8 +1290,7 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) { // See comments in ParseIfStatement for why we create a scope for the // condition and a new scope for substatement in C++. // - ParseScope InnerScope(this, Scope::DeclScope, - C99orCXX && Tok.isNot(tok::l_brace)); + ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); // Read the body statement. StmtResult Body(ParseStatement(TrailingElseLoc)); @@ -1335,9 +1331,8 @@ StmtResult Parser::ParseDoStatement() { // The substatement in an iteration-statement implicitly defines a local scope // which is entered and exited each time through the loop. // - ParseScope InnerScope(this, Scope::DeclScope, - (getLangOpts().C99 || getLangOpts().CPlusPlus) && - Tok.isNot(tok::l_brace)); + bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus; + ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); // Read the body statement. StmtResult Body(ParseStatement()); @@ -1624,8 +1619,15 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { // See comments in ParseIfStatement for why we create a scope for // for-init-statement/condition and a new scope for substatement in C++. // - ParseScope InnerScope(this, Scope::DeclScope, - C99orCXXorObjC && Tok.isNot(tok::l_brace)); + ParseScope InnerScope(this, Scope::DeclScope, C99orCXXorObjC, + Tok.is(tok::l_brace)); + + // The body of the for loop has the same local mangling number as the + // for-init-statement. + // It will only be incremented if the body contains other things that would + // normally increment the mangling number (like a compound statement). + if (C99orCXXorObjC) + getCurScope()->decrementMSLocalManglingNumber(); // Read the body statement. StmtResult Body(ParseStatement(TrailingElseLoc)); diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp index eef55d31947..494768d66a6 100644 --- a/clang/lib/Sema/Scope.cpp +++ b/clang/lib/Sema/Scope.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/Scope.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; @@ -36,16 +37,24 @@ void Scope::Init(Scope *parent, unsigned flags) { FnParent = parent->FnParent; BlockParent = parent->BlockParent; TemplateParamParent = parent->TemplateParamParent; + MSLocalManglingParent = parent->MSLocalManglingParent; } else { Depth = 0; PrototypeDepth = 0; PrototypeIndex = 0; - FnParent = BlockParent = 0; + MSLocalManglingParent = FnParent = BlockParent = 0; TemplateParamParent = 0; + MSLocalManglingNumber = 1; } // If this scope is a function or contains breaks/continues, remember it. if (flags & FnScope) FnParent = this; + // The MS mangler uses the number of scopes that can hold declarations as + // part of an external name. + if (Flags & (ClassScope | FnScope)) { + MSLocalManglingNumber = getMSLocalManglingNumber(); + MSLocalManglingParent = this; + } if (flags & BreakScope) BreakParent = this; if (flags & ContinueScope) ContinueParent = this; if (flags & BlockScope) BlockParent = this; @@ -53,6 +62,16 @@ void Scope::Init(Scope *parent, unsigned flags) { // If this is a prototype scope, record that. if (flags & FunctionPrototypeScope) PrototypeDepth++; + if (flags & DeclScope) { + if (flags & FunctionPrototypeScope) + ; // Prototype scopes are uninteresting. + else if ((flags & ClassScope) && getParent()->isClassScope()) + ; // Nested class scopes aren't ambiguous. + else if ((flags & ClassScope) && getParent()->getFlags() == DeclScope) + ; // Classes inside of namespaces aren't ambiguous. + else + incrementMSLocalManglingNumber(); + } DeclsInScope.clear(); UsingDirectives.clear(); @@ -84,3 +103,77 @@ void Scope::AddFlags(unsigned FlagsToSet) { Flags |= FlagsToSet; } +void Scope::dump() const { dumpImpl(llvm::errs()); } + +void Scope::dumpImpl(raw_ostream &OS) const { + unsigned Flags = getFlags(); + bool HasFlags = Flags != 0; + + if (HasFlags) + OS << "Flags: "; + + while (Flags) { + if (Flags & FnScope) { + OS << "FnScope"; + Flags &= ~FnScope; + } else if (Flags & BreakScope) { + OS << "BreakScope"; + Flags &= ~BreakScope; + } else if (Flags & ContinueScope) { + OS << "ContinueScope"; + Flags &= ~ContinueScope; + } else if (Flags & DeclScope) { + OS << "DeclScope"; + Flags &= ~DeclScope; + } else if (Flags & ControlScope) { + OS << "ControlScope"; + Flags &= ~ControlScope; + } else if (Flags & ClassScope) { + OS << "ClassScope"; + Flags &= ~ClassScope; + } else if (Flags & BlockScope) { + OS << "BlockScope"; + Flags &= ~BlockScope; + } else if (Flags & TemplateParamScope) { + OS << "TemplateParamScope"; + Flags &= ~TemplateParamScope; + } else if (Flags & FunctionPrototypeScope) { + OS << "FunctionPrototypeScope"; + Flags &= ~FunctionPrototypeScope; + } else if (Flags & FunctionDeclarationScope) { + OS << "FunctionDeclarationScope"; + Flags &= ~FunctionDeclarationScope; + } else if (Flags & AtCatchScope) { + OS << "AtCatchScope"; + Flags &= ~AtCatchScope; + } else if (Flags & ObjCMethodScope) { + OS << "ObjCMethodScope"; + Flags &= ~ObjCMethodScope; + } else if (Flags & SwitchScope) { + OS << "SwitchScope"; + Flags &= ~SwitchScope; + } else if (Flags & TryScope) { + OS << "TryScope"; + Flags &= ~TryScope; + } else if (Flags & FnTryCatchScope) { + OS << "FnTryCatchScope"; + Flags &= ~FnTryCatchScope; + } else if (Flags & OpenMPDirectiveScope) { + OS << "OpenMPDirectiveScope"; + Flags &= ~OpenMPDirectiveScope; + } + + if (Flags) + OS << " | "; + } + if (HasFlags) + OS << '\n'; + + if (const Scope *Parent = getParent()) + OS << "Parent: (clang::Scope*)" << Parent << '\n'; + + OS << "Depth: " << Depth << '\n'; + OS << "MSLocalManglingNumber: " << getMSLocalManglingNumber() << '\n'; + if (const DeclContext *DC = getEntity()) + OS << "Entity : (clang::DeclContext*)" << DC << '\n'; +} diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index abcd886da6b..71a79b22616 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3157,7 +3157,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg()); } -static void HandleTagNumbering(Sema &S, const TagDecl *Tag) { +static void HandleTagNumbering(Sema &S, const TagDecl *Tag, Scope *TagScope) { if (!S.Context.getLangOpts().CPlusPlus) return; @@ -3168,7 +3168,7 @@ static void HandleTagNumbering(Sema &S, const TagDecl *Tag) { return; MangleNumberingContext &MCtx = S.Context.getManglingNumberContext(Tag->getParent()); - S.Context.setManglingNumber(Tag, MCtx.getManglingNumber(Tag)); + S.Context.setManglingNumber(Tag, MCtx.getManglingNumber(Tag, TagScope)); return; } @@ -3177,7 +3177,7 @@ static void HandleTagNumbering(Sema &S, const TagDecl *Tag) { if (MangleNumberingContext *MCtx = S.getCurrentMangleNumberContext(Tag->getDeclContext(), ManglingContextDecl)) { - S.Context.setManglingNumber(Tag, MCtx->getManglingNumber(Tag)); + S.Context.setManglingNumber(Tag, MCtx->getManglingNumber(Tag, TagScope)); } } @@ -3210,7 +3210,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, } if (Tag) { - HandleTagNumbering(*this, Tag); + HandleTagNumbering(*this, Tag, S); Tag->setFreeStanding(); if (Tag->isInvalidDecl()) return Tag; @@ -3810,6 +3810,18 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Chain, false)) Invalid = true; + if (VarDecl *NewVD = dyn_cast<VarDecl>(Anon)) { + if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) { + Decl *ManglingContextDecl; + if (MangleNumberingContext *MCtx = + getCurrentMangleNumberContext(NewVD->getDeclContext(), + ManglingContextDecl)) { + Context.setManglingNumber(NewVD, MCtx->getManglingNumber(NewVD, S)); + Context.setStaticLocalNumber(NewVD, MCtx->getStaticLocalNumber(NewVD)); + } + } + } + if (Invalid) Anon->setInvalidDecl(); @@ -5470,7 +5482,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(NewVD->getDeclContext(), ManglingContextDecl)) { - Context.setManglingNumber(NewVD, MCtx->getManglingNumber(NewVD)); + Context.setManglingNumber(NewVD, MCtx->getManglingNumber(NewVD, S)); + Context.setStaticLocalNumber(NewVD, MCtx->getStaticLocalNumber(NewVD)); } } @@ -8990,7 +9003,7 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, if (DeclSpec::isDeclRep(DS.getTypeSpecType())) { if (TagDecl *Tag = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl())) { - HandleTagNumbering(*this, Tag); + HandleTagNumbering(*this, Tag, S); if (!Tag->hasNameForLinkage() && !Tag->hasDeclaratorForAnonDecl()) Tag->setDeclaratorForAnonDecl(FirstDeclaratorInGroup); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6439b9208c4..9bfdc5f95ec 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3636,6 +3636,7 @@ void Sema::BuildVariableInstantiation( // Forward the mangling number from the template to the instantiated decl. Context.setManglingNumber(NewVar, Context.getManglingNumber(OldVar)); + Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar)); // Delay instantiation of the initializer for variable templates until a // definition of the variable is needed. diff --git a/clang/test/CodeGenCXX/mangle-ms-abi-examples.cpp b/clang/test/CodeGenCXX/mangle-ms-abi-examples.cpp index 182d00d0c44..5dc9d2e71da 100644 --- a/clang/test/CodeGenCXX/mangle-ms-abi-examples.cpp +++ b/clang/test/CodeGenCXX/mangle-ms-abi-examples.cpp @@ -11,7 +11,7 @@ struct A { B(); } }; -void foo () { +inline void foo () { struct C { struct D { virtual ~D() {} }; void bar () { @@ -25,4 +25,6 @@ void foo () { C::D(); C().bar(); } - +void call () { + foo(); +} diff --git a/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp b/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp index e25f21e3962..2074c7e7efb 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp @@ -24,8 +24,8 @@ void StaticLocal() { static S TheS; } // CHECK-LABEL: define void @"\01?StaticLocal@@YAXXZ"() -// CHECK: load i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA" -// CHECK: store i32 {{.*}}, i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA" +// CHECK: load i32* @"\01?$S1@?0??StaticLocal@@YAXXZ@4IA" +// CHECK: store i32 {{.*}}, i32* @"\01?$S1@?0??StaticLocal@@YAXXZ@4IA" // CHECK: ret void MultipleStatics() { @@ -66,7 +66,7 @@ void MultipleStatics() { static S S35; } // CHECK-LABEL: define void @"\01?MultipleStatics@@YAXXZ"() -// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA" +// CHECK: load i32* @"\01?$S1@?0??MultipleStatics@@YAXXZ@4IA" // CHECK: and i32 {{.*}}, 1 // CHECK: and i32 {{.*}}, 2 // CHECK: and i32 {{.*}}, 4 @@ -74,7 +74,7 @@ void MultipleStatics() { // CHECK: and i32 {{.*}}, 16 // ... // CHECK: and i32 {{.*}}, -2147483648 -// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA1" +// CHECK: load i32* @"\01?$S1@?0??MultipleStatics@@YAXXZ@4IA1" // CHECK: and i32 {{.*}}, 1 // CHECK: and i32 {{.*}}, 2 // CHECK: and i32 {{.*}}, 4 |