Index: src/CodeGen/CodeGenerator.cc
===================================================================
--- src/CodeGen/CodeGenerator.cc	(revision 64071c2ad8eac1915b692988a8dc0d8e9d7cb8da)
+++ src/CodeGen/CodeGenerator.cc	(revision 7baed7d624d6fc245ee9ff6f08edb3226adfc288)
@@ -26,4 +26,5 @@
 #include "SynTree/Statement.h"
 #include "SynTree/Type.h"
+#include "SynTree/Attribute.h"
 
 #include "Common/utility.h"
@@ -76,26 +77,24 @@
 	}
 
+	void CodeGenerator::genAttributes( std::list< Attribute * > & attributes ) {
+		if ( ! attributes.empty() ) {
+			output << "__attribute__ ((";
+			for ( Attribute *& attr : attributes ) {
+				if ( ! attr->empty() ) {
+					output << attr->get_name() << "(";
+					genCommaList( attr->get_parameters().begin(), attr->get_parameters().end() );
+					output << ")";
+				}
+				output << ",";
+			}
+			output << ")) ";
+		}
+	}
+
+
 	//*** Declarations
 	void CodeGenerator::visit( FunctionDecl *functionDecl ) {
-		// generalize this
-		FunctionDecl::Attribute attr = functionDecl->get_attribute();
-		switch ( attr.type ) {
-			case FunctionDecl::Attribute::Constructor:
-				output << "__attribute__ ((constructor";
-				if ( attr.priority != FunctionDecl::Attribute::Default ) {
-					output << "(" << attr.priority << ")";
-				}
-				output << ")) ";
-				break;
-			case FunctionDecl::Attribute::Destructor:
-				output << "__attribute__ ((destructor";
-				if ( attr.priority != FunctionDecl::Attribute::Default ) {
-					output << "(" << attr.priority << ")";
-				}
-				output << ")) ";
-				break;
-			default:
-				break;
-		}
+		genAttributes( functionDecl->get_attributes() );
+
 		handleStorageClass( functionDecl );
 		if ( functionDecl->get_isInline() ) {
Index: src/CodeGen/CodeGenerator.h
===================================================================
--- src/CodeGen/CodeGenerator.h	(revision 64071c2ad8eac1915b692988a8dc0d8e9d7cb8da)
+++ src/CodeGen/CodeGenerator.h	(revision 7baed7d624d6fc245ee9ff6f08edb3226adfc288)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// CodeGenerator.h -- 
+// CodeGenerator.h --
 //
 // Author           : Richard C. Bilson
@@ -60,5 +60,5 @@
 		virtual void visit( MemberExpr *memberExpr );
 		virtual void visit( VariableExpr *variableExpr );
-		virtual void visit( ConstantExpr *constantExpr ); 
+		virtual void visit( ConstantExpr *constantExpr );
 		virtual void visit( SizeofExpr *sizeofExpr );
 		virtual void visit( AlignofExpr *alignofExpr );
@@ -85,5 +85,7 @@
 		virtual void visit( ForStmt * );
 		virtual void visit( NullStmt * );
-		virtual void visit( DeclStmt * ); 
+		virtual void visit( DeclStmt * );
+
+		void genAttributes( std::list< Attribute * > & attributes );
 
 		template< class Iterator > void genCommaList( Iterator begin, Iterator end );
@@ -108,5 +110,5 @@
 
 	};
-	
+
 	template< class Iterator >
 	void CodeGenerator::genCommaList( Iterator begin, Iterator end ) {
@@ -119,5 +121,5 @@
 		} // for
 	}
-  
+
 	inline bool doSemicolon( Declaration* decl ) {
 		if ( FunctionDecl* func = dynamic_cast< FunctionDecl* >( decl ) ) {
Index: src/InitTweak/FixGlobalInit.cc
===================================================================
--- src/InitTweak/FixGlobalInit.cc	(revision 64071c2ad8eac1915b692988a8dc0d8e9d7cb8da)
+++ src/InitTweak/FixGlobalInit.cc	(revision 7baed7d624d6fc245ee9ff6f08edb3226adfc288)
@@ -22,4 +22,5 @@
 #include "SynTree/Initializer.h"
 #include "SynTree/Visitor.h"
+#include "SynTree/Attribute.h"
 #include <algorithm>
 
@@ -116,7 +117,20 @@
 	GlobalFixer::GlobalFixer( const std::string & name, bool inLibrary ) : tempNamer( "_global_init" ) {
 		std::string fixedName = globalFunctionName( name );
-		initFunction = new FunctionDecl( "_init_" + fixedName, DeclarationNode::Static, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false, FunctionDecl::Attribute( FunctionDecl::Attribute::Constructor, inLibrary ? FunctionDecl::Attribute::High : FunctionDecl::Attribute::Default ) );
-
-		destroyFunction = new FunctionDecl( "_destroy_" + fixedName, DeclarationNode::Static, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false, FunctionDecl::Attribute( FunctionDecl::Attribute::Destructor, inLibrary ? FunctionDecl::Attribute::High : FunctionDecl::Attribute::Default ) );
+		std::list< Expression * > ctorParameters;
+		std::list< Expression * > dtorParameters;
+		if ( inLibrary ) {
+			// Constructor/destructor attributes take a single parameter which
+			// is the priority, with lower numbers meaning higher priority.
+			// Functions specified with priority are guaranteed to run before
+			// functions without a priority. To ensure that constructors and destructors
+			// for library code are run before constructors and destructors for user code,
+			// specify a priority when building the library. Priorities 0-100 are reserved by gcc.
+			ctorParameters.push_back( new ConstantExpr( Constant::from_int( 101 ) ) );
+			dtorParameters.push_back( new ConstantExpr( Constant::from_int( 101 ) ) );
+		}
+		initFunction = new FunctionDecl( "_init_" + fixedName, DeclarationNode::Static, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false );
+		initFunction->get_attributes().push_back( new Attribute( "constructor", ctorParameters ) );
+		destroyFunction = new FunctionDecl( "_destroy_" + fixedName, DeclarationNode::Static, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false );
+		destroyFunction->get_attributes().push_back( new Attribute( "destructor", dtorParameters ) );
 	}
 
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision 64071c2ad8eac1915b692988a8dc0d8e9d7cb8da)
+++ src/Makefile.in	(revision 7baed7d624d6fc245ee9ff6f08edb3226adfc288)
@@ -195,4 +195,5 @@
 	SynTree/driver_cfa_cpp-Mutator.$(OBJEXT) \
 	SynTree/driver_cfa_cpp-TypeSubstitution.$(OBJEXT) \
+	SynTree/driver_cfa_cpp-Attribute.$(OBJEXT) \
 	Tuples/driver_cfa_cpp-Mutate.$(OBJEXT) \
 	Tuples/driver_cfa_cpp-AssignExpand.$(OBJEXT) \
@@ -383,8 +384,8 @@
 	SynTree/NamedTypeDecl.cc SynTree/TypeDecl.cc \
 	SynTree/Initializer.cc SynTree/Visitor.cc SynTree/Mutator.cc \
-	SynTree/TypeSubstitution.cc Tuples/Mutate.cc \
-	Tuples/AssignExpand.cc Tuples/FunctionFixer.cc \
-	Tuples/TupleAssignment.cc Tuples/FunctionChecker.cc \
-	Tuples/NameMatcher.cc
+	SynTree/TypeSubstitution.cc SynTree/Attribute.cc \
+	Tuples/Mutate.cc Tuples/AssignExpand.cc \
+	Tuples/FunctionFixer.cc Tuples/TupleAssignment.cc \
+	Tuples/FunctionChecker.cc Tuples/NameMatcher.cc
 MAINTAINERCLEANFILES = Parser/parser.output ${libdir}/${notdir \
 	${cfa_cpplib_PROGRAMS}}
@@ -755,4 +756,6 @@
 SynTree/driver_cfa_cpp-TypeSubstitution.$(OBJEXT):  \
 	SynTree/$(am__dirstamp) SynTree/$(DEPDIR)/$(am__dirstamp)
+SynTree/driver_cfa_cpp-Attribute.$(OBJEXT): SynTree/$(am__dirstamp) \
+	SynTree/$(DEPDIR)/$(am__dirstamp)
 Tuples/$(am__dirstamp):
 	@$(MKDIR_P) Tuples
@@ -852,4 +855,5 @@
 	-rm -f SynTree/driver_cfa_cpp-ArrayType.$(OBJEXT)
 	-rm -f SynTree/driver_cfa_cpp-AttrType.$(OBJEXT)
+	-rm -f SynTree/driver_cfa_cpp-Attribute.$(OBJEXT)
 	-rm -f SynTree/driver_cfa_cpp-BasicType.$(OBJEXT)
 	-rm -f SynTree/driver_cfa_cpp-CommaExpr.$(OBJEXT)
@@ -961,4 +965,5 @@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-ArrayType.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-AttrType.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-Attribute.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-BasicType.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-CommaExpr.Po@am__quote@
@@ -2396,4 +2401,18 @@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-TypeSubstitution.obj `if test -f 'SynTree/TypeSubstitution.cc'; then $(CYGPATH_W) 'SynTree/TypeSubstitution.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/TypeSubstitution.cc'; fi`
+
+SynTree/driver_cfa_cpp-Attribute.o: SynTree/Attribute.cc
+@am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT SynTree/driver_cfa_cpp-Attribute.o -MD -MP -MF SynTree/$(DEPDIR)/driver_cfa_cpp-Attribute.Tpo -c -o SynTree/driver_cfa_cpp-Attribute.o `test -f 'SynTree/Attribute.cc' || echo '$(srcdir)/'`SynTree/Attribute.cc
+@am__fastdepCXX_TRUE@	$(am__mv) SynTree/$(DEPDIR)/driver_cfa_cpp-Attribute.Tpo SynTree/$(DEPDIR)/driver_cfa_cpp-Attribute.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='SynTree/Attribute.cc' object='SynTree/driver_cfa_cpp-Attribute.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-Attribute.o `test -f 'SynTree/Attribute.cc' || echo '$(srcdir)/'`SynTree/Attribute.cc
+
+SynTree/driver_cfa_cpp-Attribute.obj: SynTree/Attribute.cc
+@am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT SynTree/driver_cfa_cpp-Attribute.obj -MD -MP -MF SynTree/$(DEPDIR)/driver_cfa_cpp-Attribute.Tpo -c -o SynTree/driver_cfa_cpp-Attribute.obj `if test -f 'SynTree/Attribute.cc'; then $(CYGPATH_W) 'SynTree/Attribute.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/Attribute.cc'; fi`
+@am__fastdepCXX_TRUE@	$(am__mv) SynTree/$(DEPDIR)/driver_cfa_cpp-Attribute.Tpo SynTree/$(DEPDIR)/driver_cfa_cpp-Attribute.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='SynTree/Attribute.cc' object='SynTree/driver_cfa_cpp-Attribute.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-Attribute.obj `if test -f 'SynTree/Attribute.cc'; then $(CYGPATH_W) 'SynTree/Attribute.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/Attribute.cc'; fi`
 
 Tuples/driver_cfa_cpp-Mutate.o: Tuples/Mutate.cc
Index: src/SynTree/Declaration.h
===================================================================
--- src/SynTree/Declaration.h	(revision 64071c2ad8eac1915b692988a8dc0d8e9d7cb8da)
+++ src/SynTree/Declaration.h	(revision 7baed7d624d6fc245ee9ff6f08edb3226adfc288)
@@ -115,17 +115,5 @@
 	typedef DeclarationWithType Parent;
   public:
-	// temporary - merge this into general GCC attributes
-	struct Attribute {
-		enum Type {
-			NoAttribute, Constructor, Destructor,
-		} type;
-		enum Priority {
-			// priorities 0-100 are reserved by gcc, so it's okay to use 100 an exceptional case
-			Default = 100, High,
-		} priority;
-		Attribute(Type t = NoAttribute, Priority p = Default) : type(t), priority(p) {};
-	};
-
-	FunctionDecl( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage, FunctionType *type, CompoundStmt *statements, bool isInline, bool isNoreturn, Attribute attribute = Attribute() );
+	FunctionDecl( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage, FunctionType *type, CompoundStmt *statements, bool isInline, bool isNoreturn, const std::list< Attribute * > attributes = std::list< Attribute * >() );
 	FunctionDecl( const FunctionDecl &other );
 	virtual ~FunctionDecl();
@@ -140,6 +128,5 @@
 	std::list< std::string >& get_oldIdents() { return oldIdents; }
 	std::list< Declaration* >& get_oldDecls() { return oldDecls; }
-	Attribute get_attribute() const { return attribute; }
-	void set_attribute( Attribute newValue ) { attribute = newValue; }
+	std::list< Attribute * >& get_attributes() { return attributes; }
 
 	virtual FunctionDecl *clone() const { return new FunctionDecl( *this ); }
@@ -153,5 +140,5 @@
 	std::list< std::string > oldIdents;
 	std::list< Declaration* > oldDecls;
-	Attribute attribute;
+	std::list< Attribute * > attributes;
 };
 
Index: src/SynTree/FunctionDecl.cc
===================================================================
--- src/SynTree/FunctionDecl.cc	(revision 64071c2ad8eac1915b692988a8dc0d8e9d7cb8da)
+++ src/SynTree/FunctionDecl.cc	(revision 7baed7d624d6fc245ee9ff6f08edb3226adfc288)
@@ -19,8 +19,9 @@
 #include "Statement.h"
 #include "Type.h"
+#include "Attribute.h"
 #include "Common/utility.h"
 
-FunctionDecl::FunctionDecl( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage, FunctionType *type, CompoundStmt *statements, bool isInline, bool isNoreturn, Attribute attribute )
-		: Parent( name, sc, linkage ), type( type ), statements( statements ), attribute( attribute ) {
+FunctionDecl::FunctionDecl( const std::string &name, DeclarationNode::StorageClass sc, LinkageSpec::Type linkage, FunctionType *type, CompoundStmt *statements, bool isInline, bool isNoreturn, std::list< Attribute * > attributes )
+		: Parent( name, sc, linkage ), type( type ), statements( statements ), attributes( attributes ) {
 	set_isInline( isInline );
 	set_isNoreturn( isNoreturn );
@@ -32,5 +33,6 @@
 
 FunctionDecl::FunctionDecl( const FunctionDecl &other )
-	: Parent( other ), type( maybeClone( other.type ) ), statements( maybeClone( other.statements ) ), attribute( other.attribute ) {
+	: Parent( other ), type( maybeClone( other.type ) ), statements( maybeClone( other.statements ) ) {
+		cloneAll( other.attributes, attributes );
 }
 
@@ -38,4 +40,5 @@
 	delete type;
 	delete statements;
+	deleteAll( attributes );
 }
 
@@ -65,17 +68,7 @@
 		os << "_Noreturn ";
 	} // if
-	switch ( attribute.type ) {
-		case Attribute::Constructor:
-			os << "Global Constructor ";
-			break;
-		case Attribute::Destructor:
-			os << "Global Destructor ";
-			break;
-		default:
-			break;
-	}
-	if ( attribute.priority != Attribute::Default ) {
-		os << "with priority " << attribute.priority << " ";
-	}
+
+	printAll( attributes, os, indent );
+
 	if ( get_storageClass() != DeclarationNode::NoStorageClass ) {
 		os << DeclarationNode::storageName[ get_storageClass() ] << ' ';
@@ -118,17 +111,7 @@
 		os << "_Noreturn ";
 	} // if
-	switch ( attribute.type ) {
-		case Attribute::Constructor:
-			os << " Global Constructor ";
-			break;
-		case Attribute::Destructor:
-			os << " Global Destructor ";
-			break;
-		default:
-			break;
-	}
-	if ( attribute.priority != Attribute::Default ) {
-		os << "with priority " << attribute.priority << " ";
-	}
+
+	// xxx - should printShort print attributes?
+
 	if ( get_storageClass() != DeclarationNode::NoStorageClass ) {
 		os << DeclarationNode::storageName[ get_storageClass() ] << ' ';
Index: src/SynTree/SynTree.h
===================================================================
--- src/SynTree/SynTree.h	(revision 64071c2ad8eac1915b692988a8dc0d8e9d7cb8da)
+++ src/SynTree/SynTree.h	(revision 7baed7d624d6fc245ee9ff6f08edb3226adfc288)
@@ -118,4 +118,7 @@
 class TypeSubstitution;
 
+// gcc attribute
+class Attribute;
+
 #endif // SYNTREE_H
 
Index: src/SynTree/module.mk
===================================================================
--- src/SynTree/module.mk	(revision 64071c2ad8eac1915b692988a8dc0d8e9d7cb8da)
+++ src/SynTree/module.mk	(revision 7baed7d624d6fc245ee9ff6f08edb3226adfc288)
@@ -6,5 +6,5 @@
 ## file "LICENCE" distributed with Cforall.
 ##
-## module.mk -- 
+## module.mk --
 ##
 ## Author           : Richard C. Bilson
@@ -46,4 +46,5 @@
        SynTree/Visitor.cc \
        SynTree/Mutator.cc \
-       SynTree/TypeSubstitution.cc
+       SynTree/TypeSubstitution.cc \
+       SynTree/Attribute.cc
 
