[cfe-commits] [PATCH] Constructor and Destructor mangling, along with improved Calling Convention handling for Windows.

Charles Davis cdavis at mymail.mines.edu
Thu Jan 20 22:05:12 PST 2011


On 1/20/11 10:12 PM, Ricky Taylor wrote:
> Hello,
> 
> I've created a patch for clang, that addresses some issues with the
> Microsoft ABI:
> 
> - Constructors and Destructors are now mangled correctly
> - 'Repeated Namespaces' are mangled correctly
> - The correct default calling convention is used for class/struct methods
> - __declspec syntax is now used, (and presumably the GCC equivalent).
> - Attributes are passed down the chain correctly, (they were not being
> copied into the Declarator).
> 
> The patch is attached below,
Hi,

I wrote the Microsoft C++ Mangler initially. Comments below:

Index: include/clang/Sema/DeclSpec.h
===================================================================
--- include/clang/Sema/DeclSpec.h	(revision 123612)
+++ include/clang/Sema/DeclSpec.h	(working copy)
@@ -1206,7 +1206,7 @@
   Declarator(const DeclSpec &ds, TheContext C)
     : DS(ds), Range(ds.getSourceRange()), Context(C),
       InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
-      GroupingParens(false), AttrList(0), AsmLabel(0),
+	  GroupingParens(false), AttrList(ds.getAttributes().getList()),
AsmLabel(0),
       InlineParamsUsed(false), Extension(false) {
   }

I think there's a reason they weren't being passed down. I'm not sure
about Microsoft attributes, but IIRC GNU attributes on the decl-spec
belong to the type, not the declarator. Maybe we should pass down only
Microsoft (i.e. __declspec) attributes.

Also, you used tab characters instead of spaces. Please don't do that.
Lots of people use a tab width of 8, so the indentation looks off.

Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp	(revision 123612)
+++ lib/AST/ASTContext.cpp	(working copy)
@@ -885,6 +885,14 @@
   return toCharUnitsFromBits(getTypeAlign(T));
 }

+/// getDefaultCallingConvForDeclarator - Determines the default calling
convention
+/// for a Declarator before attributes are applied.
+CallingConv ASTContext::getDefaultCallingConvForDeclarator(Declarator
&D, Scope *S) const
+{
+	// Pass through to ABI.
+	return ABI->getDefaultCallingConvForDeclarator(D, S);
+}
+

You could avoid having to add another method to the C++ ABI object by
calling the getDefaultMethodCallingConv() method on the ABI object. Then
this becomes:

  CallingConv getDefaultCallingConvForDeclarator(Declarator &D, Scope
*S) const {
	  if(<the declarator refers to an instance method>)
		  return ABI->getDefaultMethodCallingConv();

	  return CC_C;
  }


Index: lib/AST/CXXABI.h
===================================================================
--- lib/AST/CXXABI.h	(revision 123612)
+++ lib/AST/CXXABI.h	(working copy)
@@ -21,6 +21,8 @@

 class ASTContext;
 class MemberPointerType;
+class Declarator;
+class Scope;

 /// Implements C++ ABI-specific semantic analysis functions.
 class CXXABI {
@@ -30,10 +32,13 @@
   /// Returns the size of a member pointer in multiples of the target
   /// pointer size.
   virtual unsigned getMemberPointerSize(const MemberPointerType *MPT)
const = 0;
-
+
   /// Returns the default calling convention for C++ methods.
   virtual CallingConv getDefaultMethodCallConv() const = 0;

+  /// Returns the default calling convention for a particular Declarator.
+  virtual CallingConv getDefaultCallingConvForDeclarator(Declarator &D,
Scope *S) const = 0;
+

You shouldn't have to do this (see above).

Index: lib/AST/MicrosoftCXXABI.cpp
===================================================================
--- lib/AST/MicrosoftCXXABI.cpp	(revision 123612)
+++ lib/AST/MicrosoftCXXABI.cpp	(working copy)
@@ -17,6 +17,8 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/AST/Type.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Scope.h"
 #include "clang/Basic/TargetInfo.h"

 using namespace clang;
@@ -36,6 +38,13 @@
       return CC_C;
   }

+  CallingConv getDefaultCallingConvForDeclarator(Declarator &D, Scope
*S) const {
+	  if(S && (S->getFlags() & Scope::ClassScope))
+		  return CC_X86ThisCall;
+
+	  return CC_C;
+  }
+

You should probably make sure that the declarator doesn't have the
static storage class. For static methods, the default calling convention
is still __cdecl. (Of course, this is after moving the implementation
over to ASTContext.)

Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp	(revision 123612)
+++ lib/AST/MicrosoftMangle.cpp	(working copy)
@@ -30,6 +30,7 @@
 class MicrosoftCXXNameMangler {
   MangleContext &Context;
   llvm::raw_svector_ostream Out;
+  std::vector<llvm::StringRef> Shortcuts;

You might consider using a SmallVector here (there can only be 10
replacements anyway).

   ASTContext &getASTContext() const { return Context.getASTContext(); }

@@ -336,11 +337,13 @@
       break;

     case DeclarationName::CXXConstructorName:
-      assert(false && "Can't mangle constructors yet!");
+	  // <constructor> ::= ?0 class-name
+	  Out << "?0";
       break;

Tabs.

     case DeclarationName::CXXDestructorName:
-      assert(false && "Can't mangle destructors yet!");
+	  // <destructor> ::= ?1
+      Out << "?1";
       break;

Tabs again. (The second line is okay, though.)

     case DeclarationName::CXXConversionFunctionName:
@@ -382,7 +385,8 @@
   if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
     llvm::SmallString<64> Name;
     Context.mangleBlock(BD, Name);
-    Out << Name << '@';
+
+	Out << Name << '@';
     return manglePostfix(DC->getParent(), NoFunction);
   }

Please avoid gratuitous whitespace changes.

@@ -525,8 +529,34 @@
 }

 void MicrosoftCXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
-  // <source name> ::= <identifier> @
-  Out << II->getName() << '@';
+	// <source name> ::= <identifier> @
+
+	llvm::StringRef Name = II->getName();
+
+	// Microsoft assign the first 10 names to ascii shortcuts
+	// '0'-'9'. They are then used instead of the name@ syntax.
+	bool newName = true;
+	for(size_t i = 0; i < Shortcuts.size(); i++)
+	{
+		if(Shortcuts[i].compare(Name) == 0)
+		{
+			Out << std::string(1, '0' + i);
+			newName = false;
+			break;
+		}
+	}
+
+	// If we weren't in the shortcut list, then we will have to
+	// write the whole name out.
+	if(newName)
+	{
+		Out << Name << '@';
+
+		if(Shortcuts.size() < 10)
+		{
+			Shortcuts.push_back(Name);
+		}
+	}
 }

You should probably add a test for this to
<clang>/test/CodeGenCXX/mangle-ms.cpp.

Oh, and tabs again.

The whole patch file had mixed line endings (CR-LF and LF). Try to avoid
that.

Did you make sure to run Clang's tests with your patch, in case you
introduced a regression?

Other than those, LGTM! Doug, John, your thoughts?

Chip



More information about the cfe-commits mailing list