Index: src/Validate/HandleAttributes.cc
===================================================================
--- src/Validate/HandleAttributes.cc	(revision fd2debf6bc04a25e7312e0b1f5ff93f7d5aff352)
+++ src/Validate/HandleAttributes.cc	(revision fd2debf6bc04a25e7312e0b1f5ff93f7d5aff352)
@@ -0,0 +1,160 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// HandleAttributes.cc --
+//
+// Author           : Rob Schluntz
+// Created On       : Fri Jul 27 10:15:06 2018
+// Last Modified By : Rob Schluntz
+// Last Modified On : Fri Jul 27 10:16:43 2018
+// Update Count     : 2
+//
+
+#include "HandleAttributes.h"
+
+#include <utility> // for pair
+
+#include "CompilationState.h"
+#include "Common/PassVisitor.h"
+#include "Common/SemanticError.h"
+#include "InitTweak/InitTweak.h"
+#include "ResolvExpr/Resolver.h"
+#include "SynTree/Attribute.h"
+#include "SynTree/Declaration.h"
+#include "SynTree/Type.h"
+
+namespace Validate {
+	namespace {
+		std::pair<long long int, bool> eval(Expression * expr);
+
+		struct Eval : public WithShortCircuiting {
+			long long int value = 0;
+			bool valid = true;
+
+			void previsit( BaseSyntaxNode * ) { visit_children = false; }
+			void postvisit( BaseSyntaxNode * ) { valid = false; }
+
+			void postvisit( ConstantExpr * expr ) {
+				value = expr->intValue();
+			}
+
+			void postvisit( CastExpr * expr ) {
+				auto arg = eval(expr->arg);
+				valid = arg.second;
+				value = arg.first;
+				// TODO: perform type conversion on value if valid
+			}
+
+			void postvisit( VariableExpr * expr ) {
+				if ( EnumInstType * inst = dynamic_cast<EnumInstType *>(expr->result) ) {
+					if ( EnumDecl * decl = inst->baseEnum ) {
+						if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf
+							return;
+						}
+					}
+				}
+				valid = false;
+			}
+
+			void postvisit( ApplicationExpr * expr ) {
+				DeclarationWithType * function = InitTweak::getFunction(expr);
+				if ( ! function || function->linkage != LinkageSpec::Intrinsic ) { valid = false; return; }
+				const std::string & fname = function->name;
+				assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() );
+				std::pair<long long int, bool> arg1, arg2;
+				arg1 = eval(expr->args.front());
+				valid = valid && arg1.second;
+				if ( ! valid ) return;
+				if ( expr->args.size() == 2 ) {
+					arg2 = eval(expr->args.back());
+					valid = valid && arg2.second;
+					if ( ! valid ) return;
+				}
+				if (fname == "?+?") {
+					value = arg1.first + arg2.first;
+				} else if (fname == "?-?") {
+					value = arg1.first - arg2.first;
+				} else if (fname == "?*?") {
+					value = arg1.first * arg2.first;
+				} else if (fname == "?/?") {
+					value = arg1.first / arg2.first;
+				} else if (fname == "?%?") {
+					value = arg1.first % arg2.first;
+				} else {
+					valid = false;
+				}
+				// TODO: implement other intrinsic functions
+			}
+		};
+
+		std::pair<long long int, bool> eval(Expression * expr) {
+			PassVisitor<Eval> ev;
+			if (expr) {
+				expr->accept(ev);
+				return std::make_pair(ev.pass.value, ev.pass.valid);
+			} else {
+				return std::make_pair(0, false);
+			}
+		}
+
+		struct HandleAttributes : public WithIndexer {
+			void previsit( ObjectDecl * decl );
+			void previsit( FunctionDecl * decl );
+		};
+	} // namespace
+
+	void handleAttributes( std::list< Declaration * > &translationUnit ) {
+		PassVisitor<HandleAttributes> handler;
+		acceptAll( translationUnit, handler );
+	}
+
+	namespace {
+		void HandleAttributes::previsit( ObjectDecl * decl ) {
+			for ( Attribute * attr : decl->attributes ) {
+				std::string name = attr->normalizedName();
+				if (name == "init_priority") {
+
+				}
+			}
+		}
+
+		void HandleAttributes::previsit( FunctionDecl * decl ) {
+			for ( Attribute * attr : decl->attributes ) {
+				std::string name = attr->normalizedName();
+				if (name == "constructor" || name == "destructor") {
+					if (attr->parameters.size() == 1) {
+						Expression *& arg = attr->parameters.front();
+						ResolvExpr::findSingleExpression( arg, new BasicType( Type::Qualifiers(), BasicType::LongLongSignedInt ), indexer );
+						auto result = eval(arg);
+						if (! result.second) {
+							SemanticWarning(attr->location, Warning::GccAttributes,
+								toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) );
+							return;
+						}
+						auto priority = result.first;
+						if (priority < 101) {
+							SemanticWarning(attr->location, Warning::GccAttributes,
+								toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) );
+						} else if (priority < 201) {
+							SemanticWarning(attr->location, Warning::GccAttributes,
+								toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) );
+						}
+					} else if (attr->parameters.size() > 1) {
+						SemanticWarning(attr->location, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) );
+					} else {
+						SemanticWarning(attr->location, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) );
+					}
+				}
+			}
+		}
+	} // namespace
+} // namespace Validate
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
