diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
index 26ccd00c79a..3f1533b592f 100644
--- a/gcc/d/d-builtins.cc
+++ b/gcc/d/d-builtins.cc
@@ -311,7 +311,7 @@ build_frontend_type (tree type)
 		  return NULL;
 		}
 
-	      args->push (Parameter::create (sc, targ, NULL, NULL));
+	      args->push (Parameter::create (sc, targ, NULL, NULL, NULL));
 	    }
 
 	  /* GCC generic and placeholder built-ins are marked as variadic, yet
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 1629b4535ee..25b2b3ac965 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-a5c86f5b92c4cd3afde910c89881ccaea11de554
+9038e64c5b67a10763d32893f53bb6c610df3595
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/arrayop.c b/gcc/d/dmd/arrayop.c
index 72abd5e9b30..20cdb6fd184 100644
--- a/gcc/d/dmd/arrayop.c
+++ b/gcc/d/dmd/arrayop.c
@@ -51,7 +51,7 @@ FuncDeclaration *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc)
     Parameter *p = (*fparams)[0];
     // foreach (i; 0 .. p.length)
     Statement *s1 = new ForeachRangeStatement(Loc(), TOKforeach,
-        new Parameter(0, NULL, Id::p, NULL),
+        new Parameter(0, NULL, Id::p, NULL, NULL),
         new IntegerExp(Loc(), 0, Type::tsize_t),
         new ArrayLengthExp(Loc(), new IdentifierExp(Loc(), p->ident)),
         new ExpStatement(Loc(), loopbody),
@@ -422,7 +422,7 @@ Expression *buildArrayLoop(Expression *e, Parameters *fparams)
         void visit(Expression *e)
         {
             Identifier *id = Identifier::generateId("c", fparams->length);
-            Parameter *param = new Parameter(0, e->type, id, NULL);
+            Parameter *param = new Parameter(0, e->type, id, NULL, NULL);
             fparams->shift(param);
             result = new IdentifierExp(Loc(), id);
         }
@@ -441,7 +441,7 @@ Expression *buildArrayLoop(Expression *e, Parameters *fparams)
         void visit(ArrayLiteralExp *e)
         {
             Identifier *id = Identifier::generateId("p", fparams->length);
-            Parameter *param = new Parameter(STCconst, e->type, id, NULL);
+            Parameter *param = new Parameter(STCconst, e->type, id, NULL, NULL);
             fparams->shift(param);
             Expression *ie = new IdentifierExp(Loc(), id);
             Expression *index = new IdentifierExp(Loc(), Id::p);
@@ -451,7 +451,7 @@ Expression *buildArrayLoop(Expression *e, Parameters *fparams)
         void visit(SliceExp *e)
         {
             Identifier *id = Identifier::generateId("p", fparams->length);
-            Parameter *param = new Parameter(STCconst, e->type, id, NULL);
+            Parameter *param = new Parameter(STCconst, e->type, id, NULL, NULL);
             fparams->shift(param);
             Expression *ie = new IdentifierExp(Loc(), id);
             Expression *index = new IdentifierExp(Loc(), Id::p);
diff --git a/gcc/d/dmd/clone.c b/gcc/d/dmd/clone.c
index dd22fb340f5..73c4a660368 100644
--- a/gcc/d/dmd/clone.c
+++ b/gcc/d/dmd/clone.c
@@ -244,7 +244,7 @@ FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc)
     }
 
     Parameters *fparams = new Parameters;
-    fparams->push(new Parameter(STCnodtor, sd->type, Id::p, NULL));
+    fparams->push(new Parameter(STCnodtor, sd->type, Id::p, NULL, NULL));
     TypeFunction *tf = new TypeFunction(ParameterList(fparams), sd->handleType(), LINKd, stc | STCref);
 
     FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf);
@@ -503,7 +503,7 @@ FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc)
                 /* const bool opEquals(ref const S s);
                  */
                 Parameters *parameters = new Parameters;
-                parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL));
+                parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL, NULL));
                 tfeqptr = new TypeFunction(ParameterList(parameters), Type::tbool, LINKd);
                 tfeqptr->mod = MODconst;
                 tfeqptr = (TypeFunction *)tfeqptr->semantic(Loc(), &scx);
@@ -531,8 +531,8 @@ FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc)
     Loc loc = Loc();        // loc is unnecessary so errors are gagged
 
     Parameters *parameters = new Parameters;
-    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
-    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL));
+    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL, NULL));
+    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL, NULL));
     TypeFunction *tf = new TypeFunction(ParameterList(parameters), Type::tbool, LINKd);
 
     Identifier *id = Id::xopEquals;
@@ -583,7 +583,7 @@ FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc)
                 /* const int opCmp(ref const S s);
                  */
                 Parameters *parameters = new Parameters;
-                parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL));
+                parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL, NULL));
                 tfcmpptr = new TypeFunction(ParameterList(parameters), Type::tint32, LINKd);
                 tfcmpptr->mod = MODconst;
                 tfcmpptr = (TypeFunction *)tfcmpptr->semantic(Loc(), &scx);
@@ -616,8 +616,8 @@ FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc)
     Loc loc = Loc();        // loc is unnecessary so errors are gagged
 
     Parameters *parameters = new Parameters;
-    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
-    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL));
+    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL, NULL));
+    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL, NULL));
     TypeFunction *tf = new TypeFunction(ParameterList(parameters), Type::tint32, LINKd);
 
     Identifier *id = Id::xopCmp;
@@ -738,7 +738,7 @@ FuncDeclaration *buildXtoHash(StructDeclaration *sd, Scope *sc)
     Loc loc = Loc();        // internal code should have no loc to prevent coverage
 
     Parameters *parameters = new Parameters();
-    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
+    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL, NULL));
     TypeFunction *tf = new TypeFunction(ParameterList(parameters), Type::thash_t,
                                         LINKd, STCnothrow | STCtrusted);
 
diff --git a/gcc/d/dmd/cond.c b/gcc/d/dmd/cond.c
index 9f76e83238e..2ea3d408155 100644
--- a/gcc/d/dmd/cond.c
+++ b/gcc/d/dmd/cond.c
@@ -257,7 +257,7 @@ static void lowerNonArrayAggregate(StaticForeach *sfe, Scope *sc)
         {
             Parameters *params = pparams[j];
             Parameter *p = sfe->aggrfe ? (*sfe->aggrfe->parameters)[i] : sfe->rangefe->prm;
-            params->push(new Parameter(p->storageClass, p->type, p->ident, NULL));
+            params->push(new Parameter(p->storageClass, p->type, p->ident, NULL, NULL));
         }
     }
     Expression *res[2];
diff --git a/gcc/d/dmd/declaration.c b/gcc/d/dmd/declaration.c
index f490cc5a413..f196bc825a2 100644
--- a/gcc/d/dmd/declaration.c
+++ b/gcc/d/dmd/declaration.c
@@ -224,7 +224,7 @@ Type *TupleDeclaration::getType()
         {
             Type *t = (*types)[i];
             //printf("type = %s\n", t->toChars());
-            Parameter *arg = new Parameter(0, t, NULL, NULL);
+            Parameter *arg = new Parameter(0, t, NULL, NULL, NULL);
             (*args)[i] = arg;
             if (!t->deco)
                 hasdeco = 0;
diff --git a/gcc/d/dmd/dtemplate.c b/gcc/d/dmd/dtemplate.c
index 1035f829e12..316f105b9e3 100644
--- a/gcc/d/dmd/dtemplate.c
+++ b/gcc/d/dmd/dtemplate.c
@@ -6805,7 +6805,7 @@ bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f
                     for (size_t i = 0; i < dim; i++)
                     {
                         Parameter *arg = (*tt->arguments)[i];
-                        if (flags & 2 && arg->ident)
+                        if (flags & 2 && (arg->ident || arg->userAttribDecl))
                             tiargs->insert(j + i, arg);
                         else
                             tiargs->insert(j + i, arg->type);
diff --git a/gcc/d/dmd/expression.c b/gcc/d/dmd/expression.c
index 78918320192..a3c3f72d261 100644
--- a/gcc/d/dmd/expression.c
+++ b/gcc/d/dmd/expression.c
@@ -1953,7 +1953,7 @@ bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
         args->setDim(arguments->length - nparams);
         for (size_t i = 0; i < arguments->length - nparams; i++)
         {
-            Parameter *arg = new Parameter(STCin, (*arguments)[nparams + i]->type, NULL, NULL);
+            Parameter *arg = new Parameter(STCin, (*arguments)[nparams + i]->type, NULL, NULL, NULL);
             (*args)[i] = arg;
         }
 
diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c
index 7dfe995b711..f519389571a 100644
--- a/gcc/d/dmd/expressionsem.c
+++ b/gcc/d/dmd/expressionsem.c
@@ -2051,7 +2051,7 @@ public:
                         for (size_t i = 0; i < cd->baseclasses->length; i++)
                         {
                             BaseClass *b = (*cd->baseclasses)[i];
-                            args->push(new Parameter(STCin, b->type, NULL, NULL));
+                            args->push(new Parameter(STCin, b->type, NULL, NULL, NULL));
                         }
                         tded = new TypeTuple(args);
                     }
@@ -2100,7 +2100,8 @@ public:
                                 return setError();
                             args->push(new Parameter(arg->storageClass, arg->type,
                                                      (e->tok2 == TOKparameters) ? arg->ident : NULL,
-                                                     (e->tok2 == TOKparameters) ? arg->defaultArg : NULL));
+                                                     (e->tok2 == TOKparameters) ? arg->defaultArg : NULL,
+                                                     arg->userAttribDecl));
                         }
                         tded = new TypeTuple(args);
                         break;
diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c
index fe1ad1118e0..53621adcc41 100644
--- a/gcc/d/dmd/func.c
+++ b/gcc/d/dmd/func.c
@@ -1221,6 +1221,15 @@ Ldone:
         Compiler::genCmain(sc);
 
     assert(type->ty != Terror || errors);
+
+    // semantic for parameters' UDAs
+    const size_t nparams = f->parameterList.length();
+    for (size_t i = 0; i < nparams; i++)
+    {
+        Parameter *param = f->parameterList[i];
+        if (param && param->userAttribDecl)
+            param->userAttribDecl->semantic(sc);
+    }
 }
 
 void FuncDeclaration::semantic2(Scope *sc)
@@ -1237,6 +1246,17 @@ void FuncDeclaration::semantic2(Scope *sc)
     {
         objc()->checkLinkage(this);
     }
+    if (!type || type->ty != Tfunction)
+        return;
+    TypeFunction *f = type->toTypeFunction();
+    const size_t nparams = f->parameterList.length();
+    // semantic for parameters' UDAs
+    for (size_t i = 0; i < nparams; i++)
+    {
+        Parameter *param = f->parameterList[i];
+        if (param && param->userAttribDecl)
+            param->userAttribDecl->semantic2(sc);
+    }
 }
 
 /****************************************************
@@ -1317,7 +1337,7 @@ static void buildEnsureRequire(FuncDeclaration *fdx)
         Parameter *p = NULL;
         if (fdx->outId)
         {
-            p = new Parameter(STCref | STCconst, f->nextOf(), fdx->outId, NULL);
+            p = new Parameter(STCref | STCconst, f->nextOf(), fdx->outId, NULL, NULL);
             fparams->push(p);
         }
         TypeFunction *tf = new TypeFunction(ParameterList(fparams), Type::tvoid, LINKd);
@@ -1603,6 +1623,8 @@ void FuncDeclaration::semantic3(Scope *sc)
                     parameters->push(v);
                 localsymtab->insert(v);
                 v->parent = this;
+                if (fparam->userAttribDecl)
+                    v->userAttribDecl = fparam->userAttribDecl;
             }
         }
 
diff --git a/gcc/d/dmd/hdrgen.c b/gcc/d/dmd/hdrgen.c
index fd4d16241c4..a04a8c523a3 100644
--- a/gcc/d/dmd/hdrgen.c
+++ b/gcc/d/dmd/hdrgen.c
@@ -3097,6 +3097,18 @@ public:
 
     void visit(Parameter *p)
     {
+        if (p->userAttribDecl)
+        {
+            buf->writestring("@");
+            bool isAnonymous = p->userAttribDecl->atts->length > 0
+                && (*p->userAttribDecl->atts)[0]->op != TOKcall;
+            if (isAnonymous)
+                buf->writestring("(");
+            argsToBuffer(p->userAttribDecl->atts);
+            if (isAnonymous)
+                buf->writestring(")");
+            buf->writestring(" ");
+        }
         if (p->storageClass & STCauto)
             buf->writestring("auto ");
 
diff --git a/gcc/d/dmd/mtype.c b/gcc/d/dmd/mtype.c
index 94e2082f5b2..42f90fa9e04 100644
--- a/gcc/d/dmd/mtype.c
+++ b/gcc/d/dmd/mtype.c
@@ -1543,7 +1543,7 @@ Type *stripDefaultArgs(Type *t)
             {
                 Parameter *p = (*params)[i];
                 Type *ta = stripDefaultArgs(p->type);
-                if (ta != p->type || p->defaultArg || p->ident)
+                if (ta != p->type || p->defaultArg || p->ident || p->userAttribDecl)
                 {
                     if (params == parameters)
                     {
@@ -1552,7 +1552,7 @@ Type *stripDefaultArgs(Type *t)
                         for (size_t j = 0; j < params->length; j++)
                             (*params)[j] = (*parameters)[j];
                     }
-                    (*params)[i] = new Parameter(p->storageClass, ta, NULL, NULL);
+                    (*params)[i] = new Parameter(p->storageClass, ta, NULL, NULL, NULL);
                 }
             }
         }
@@ -1996,7 +1996,7 @@ Type *TypeFunction::substWildTo(unsigned)
             continue;
         if (params == parameterList.parameters)
             params = parameterList.parameters->copy();
-        (*params)[i] = new Parameter(p->storageClass, t, NULL, NULL);
+        (*params)[i] = new Parameter(p->storageClass, t, NULL, NULL, NULL);
     }
     if (next == tret && params == parameterList.parameters)
         return this;
@@ -4914,7 +4914,7 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int
         if (fd_aaLen == NULL)
         {
             Parameters *fparams = new Parameters();
-            fparams->push(new Parameter(STCin, this, NULL, NULL));
+            fparams->push(new Parameter(STCin, this, NULL, NULL, NULL));
             fd_aaLen = FuncDeclaration::genCfunc(fparams, Type::tsize_t, Id::aaLen);
             TypeFunction *tf = fd_aaLen->type->toTypeFunction();
             tf->purity = PUREconst;
@@ -5821,7 +5821,7 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc)
                         }
 
                         (*newparams)[j] = new Parameter(
-                                stc, narg->type, narg->ident, narg->defaultArg);
+                                stc, narg->type, narg->ident, narg->defaultArg, narg->userAttribDecl);
                     }
                     fparam->type = new TypeTuple(newparams);
                 }
@@ -9098,7 +9098,7 @@ TypeTuple::TypeTuple(Expressions *exps)
         {   Expression *e = (*exps)[i];
             if (e->type->ty == Ttuple)
                 e->error("cannot form tuple of tuples");
-            Parameter *arg = new Parameter(STCundefined, e->type, NULL, NULL);
+            Parameter *arg = new Parameter(STCundefined, e->type, NULL, NULL, NULL);
             (*arguments)[i] = arg;
         }
     }
@@ -9124,15 +9124,15 @@ TypeTuple::TypeTuple(Type *t1)
     : Type(Ttuple)
 {
     arguments = new Parameters();
-    arguments->push(new Parameter(0, t1, NULL, NULL));
+    arguments->push(new Parameter(0, t1, NULL, NULL, NULL));
 }
 
 TypeTuple::TypeTuple(Type *t1, Type *t2)
     : Type(Ttuple)
 {
     arguments = new Parameters();
-    arguments->push(new Parameter(0, t1, NULL, NULL));
-    arguments->push(new Parameter(0, t2, NULL, NULL));
+    arguments->push(new Parameter(0, t1, NULL, NULL, NULL));
+    arguments->push(new Parameter(0, t2, NULL, NULL, NULL));
 }
 
 const char *TypeTuple::kind()
@@ -9436,17 +9436,20 @@ size_t ParameterList::length()
 
 /***************************** Parameter *****************************/
 
-Parameter::Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg)
+Parameter::Parameter(StorageClass storageClass, Type *type, Identifier *ident,
+                     Expression *defaultArg, UserAttributeDeclaration *userAttribDecl)
 {
     this->type = type;
     this->ident = ident;
     this->storageClass = storageClass;
     this->defaultArg = defaultArg;
+    this->userAttribDecl = userAttribDecl;
 }
 
-Parameter *Parameter::create(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg)
+Parameter *Parameter::create(StorageClass storageClass, Type *type, Identifier *ident,
+                             Expression *defaultArg, UserAttributeDeclaration *userAttribDecl)
 {
-    return new Parameter(storageClass, type, ident, defaultArg);
+    return new Parameter(storageClass, type, ident, defaultArg, userAttribDecl);
 }
 
 Parameter *Parameter::syntaxCopy()
@@ -9454,7 +9457,8 @@ Parameter *Parameter::syntaxCopy()
     return new Parameter(storageClass,
         type ? type->syntaxCopy() : NULL,
         ident,
-        defaultArg ? defaultArg->syntaxCopy() : NULL);
+        defaultArg ? defaultArg->syntaxCopy() : NULL,
+        userAttribDecl ? (UserAttributeDeclaration *) userAttribDecl->syntaxCopy(NULL) : NULL);
 }
 
 Parameters *Parameter::arraySyntaxCopy(Parameters *parameters)
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index b0878c8f730..28dba1c250a 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -623,9 +623,12 @@ public:
     Type *type;
     Identifier *ident;
     Expression *defaultArg;
+    UserAttributeDeclaration *userAttribDecl;   // user defined attributes
 
-    Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg);
-    static Parameter *create(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg);
+    Parameter(StorageClass storageClass, Type *type, Identifier *ident,
+              Expression *defaultArg, UserAttributeDeclaration *userAttribDecl);
+    static Parameter *create(StorageClass storageClass, Type *type, Identifier *ident,
+                             Expression *defaultArg, UserAttributeDeclaration *userAttribDecl);
     Parameter *syntaxCopy();
     Type *isLazyArray();
     // kludge for template.isType()
diff --git a/gcc/d/dmd/parse.c b/gcc/d/dmd/parse.c
index be861fa92f6..e414a4d69c0 100644
--- a/gcc/d/dmd/parse.c
+++ b/gcc/d/dmd/parse.c
@@ -1110,7 +1110,7 @@ StorageClass Parser::parsePostfix(StorageClass storageClass, Expressions **pudas
                         // Disallow:
                         //      void function() @uda fp;
                         //      () @uda { return 1; }
-                        error("user defined attributes cannot appear as postfixes");
+                        error("user-defined attributes cannot appear as postfixes");
                     }
                     continue;
                 }
@@ -1979,9 +1979,11 @@ Parameters *Parser::parseParameters(VarArg *pvarargs, TemplateParameters **tpl)
         StorageClass storageClass = 0;
         StorageClass stc;
         Expression *ae;
+        Expressions *udas = NULL;
 
         for (;1; nextToken())
         {
+        L3:
             switch (token.value)
             {
                 case TOKrparen:
@@ -2016,6 +2018,28 @@ Parameters *Parser::parseParameters(VarArg *pvarargs, TemplateParameters **tpl)
                     stc = STCwild;
                     goto L2;
 
+                case TOKat:
+                {
+                    Expressions *exps = NULL;
+                    StorageClass stc2 = parseAttribute(&exps);
+                    if (stc2 == STCproperty || stc2 == STCnogc ||
+                        stc2 == STCdisable || stc2 == STCsafe ||
+                        stc2 == STCtrusted || stc2 == STCsystem)
+                    {
+                        error("`@%s` attribute for function parameter is not supported", token.toChars());
+                    }
+                    else
+                    {
+                        udas = UserAttributeDeclaration::concat(udas, exps);
+                    }
+                    if (token.value == TOKdotdotdot)
+                        error("variadic parameter cannot have user-defined attributes");
+                    if (stc2)
+                        nextToken();
+                    goto L3;
+                    // Don't call nextToken again.
+                }
+
                 case TOKin:        stc = STCin;         goto L2;
                 case TOKout:       stc = STCout;        goto L2;
                 case TOKref:       stc = STCref;        goto L2;
@@ -2068,6 +2092,30 @@ Parameters *Parser::parseParameters(VarArg *pvarargs, TemplateParameters **tpl)
                             error("default argument expected for %s",
                                     ai ? ai->toChars() : at->toChars());
                     }
+                    Parameter *param = new Parameter(storageClass, at, ai, ae, NULL);
+                    if (udas)
+                    {
+                        Dsymbols *a = new Dsymbols();
+                        UserAttributeDeclaration *udad = new UserAttributeDeclaration(udas, a);
+                        param->userAttribDecl = udad;
+                    }
+                    if (token.value == TOKat)
+                    {
+                        Expressions *exps = NULL;
+                        StorageClass stc2 = parseAttribute(&exps);
+                        if (stc2 == STCproperty || stc2 == STCnogc ||
+                            stc2 == STCdisable || stc2 == STCsafe ||
+                            stc2 == STCtrusted || stc2 == STCsystem)
+                        {
+                            error("`@%s` attribute for function parameter is not supported", token.toChars());
+                        }
+                        else
+                        {
+                            error("user-defined attributes cannot appear as postfixes", token.toChars());
+                        }
+                        if (stc2)
+                            nextToken();
+                    }
                     if (token.value == TOKdotdotdot)
                     {   /* This is:
                          *      at ai ...
@@ -2076,11 +2124,11 @@ Parameters *Parser::parseParameters(VarArg *pvarargs, TemplateParameters **tpl)
                         if (storageClass & (STCout | STCref))
                             error("variadic argument cannot be out or ref");
                         varargs = VARARGtypesafe;
-                        parameters->push(new Parameter(storageClass, at, ai, ae));
+                        parameters->push(param);
                         nextToken();
                         break;
                     }
-                    parameters->push(new Parameter(storageClass, at, ai, ae));
+                    parameters->push(param);
                     if (token.value == TOKcomma)
                     {   nextToken();
                         goto L1;
@@ -3779,6 +3827,21 @@ Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con
                     tpl = parseTemplateParameterList();
                 check(TOKassign);
 
+                bool hasParsedAttributes = false;
+                if (token.value == TOKat)
+                {
+                    if (!hasParsedAttributes)
+                    {
+                        hasParsedAttributes = true;
+                        storage_class = STCundefined;
+                        link = linkage;
+                        setAlignment = false;
+                        ealign = NULL;
+                        udas = NULL;
+                        parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
+                    }
+                }
+
                 Declaration *v;
                 if (token.value == TOKfunction ||
                     token.value == TOKdelegate ||
@@ -3796,21 +3859,39 @@ Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con
                     // identifier => expression
 
                     Dsymbol *s = parseFunctionLiteral();
+
+                    if (udas != NULL)
+                    {
+                        if (storage_class != 0)
+                            error("Cannot put a storage-class in an alias declaration.");
+                        // shouldn't have set these variables
+                        assert(link == linkage && !setAlignment && ealign == NULL);
+                        TemplateDeclaration *tpl_ = (TemplateDeclaration *) s;
+                        assert(tpl_ != NULL && tpl_->members->length == 1);
+                        FuncLiteralDeclaration *fd = (FuncLiteralDeclaration *) (*tpl_->members)[0];
+                        TypeFunction *tf = (TypeFunction *) fd->type;
+                        assert(tf->parameterList.length() > 0);
+                        Dsymbols *as = new Dsymbols();
+                        (*tf->parameterList.parameters)[0]->userAttribDecl = new UserAttributeDeclaration(udas, as);
+                    }
                     v = new AliasDeclaration(loc, ident, s);
                 }
                 else
                 {
                     // StorageClasses type
-
-                    storage_class = STCundefined;
-                    link = linkage;
-                    setAlignment = false;
-                    ealign = NULL;
-                    udas = NULL;
-                    parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
+                    if (!hasParsedAttributes)
+                    {
+                        hasParsedAttributes = true;
+                        storage_class = STCundefined;
+                        link = linkage;
+                        setAlignment = false;
+                        ealign = NULL;
+                        udas = NULL;
+                        parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
+                    }
 
                     if (udas)
-                        error("user defined attributes not allowed for %s declarations", Token::toChars(tok));
+                        error("user-defined attributes not allowed for %s declarations", Token::toChars(tok));
 
                     t = parseType();
                     v = new AliasDeclaration(loc, ident, t);
@@ -3991,7 +4072,7 @@ L2:
              */
 
             if (udas)
-                error("user defined attributes not allowed for %s declarations", Token::toChars(tok));
+                error("user-defined attributes not allowed for %s declarations", Token::toChars(tok));
 
             if (token.value == TOKassign)
             {
@@ -4221,7 +4302,7 @@ Dsymbol *Parser::parseFunctionLiteral()
             parameters = new Parameters();
             Identifier *id = Identifier::generateId("__T");
             Type *t = new TypeIdentifier(loc, id);
-            parameters->push(new Parameter(0, t, token.ident, NULL));
+            parameters->push(new Parameter(0, t, token.ident, NULL, NULL));
 
             tpl = new TemplateParameters();
             TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL);
@@ -4811,7 +4892,7 @@ Statement *Parser::parseForeach(Loc loc, bool *isRange, bool isDecl)
         if (!ai)
             error("no identifier for declarator %s", at->toChars());
       Larg:
-        Parameter *p = new Parameter(storageClass, at, ai, NULL);
+        Parameter *p = new Parameter(storageClass, at, ai, NULL, NULL);
         parameters->push(p);
         if (token.value == TOKcomma)
         {   nextToken();
@@ -5335,14 +5416,14 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc
                 Type *at = NULL;        // infer parameter type
                 nextToken();
                 check(TOKassign);
-                param = new Parameter(storageClass, at, ai, NULL);
+                param = new Parameter(storageClass, at, ai, NULL, NULL);
             }
             else if (isDeclaration(&token, 2, TOKassign, NULL))
             {
                 Identifier *ai;
                 Type *at = parseType(&ai);
                 check(TOKassign);
-                param = new Parameter(storageClass, at, ai, NULL);
+                param = new Parameter(storageClass, at, ai, NULL, NULL);
             }
 
             condition = parseExpression();
diff --git a/gcc/d/dmd/statementsem.c b/gcc/d/dmd/statementsem.c
index 4ff07f6f2eb..2fe0d9efeea 100644
--- a/gcc/d/dmd/statementsem.c
+++ b/gcc/d/dmd/statementsem.c
@@ -1494,7 +1494,7 @@ public:
                             s = new ExpStatement(Loc(), v);
                             fs->_body = new CompoundStatement(loc, s, fs->_body);
                         }
-                        params->push(new Parameter(stc, p->type, id, NULL));
+                        params->push(new Parameter(stc, p->type, id, NULL, NULL));
                     }
                     // Bugzilla 13840: Throwable nested function inside nothrow function is acceptable.
                     StorageClass stc = mergeFuncAttrs(STCsafe | STCpure | STCnogc, fs->func);
@@ -1570,15 +1570,15 @@ public:
                         if (!fdapply[i])
                         {
                             params = new Parameters();
-                            params->push(new Parameter(0, Type::tvoid->pointerTo(), NULL, NULL));
-                            params->push(new Parameter(STCin, Type::tsize_t, NULL, NULL));
+                            params->push(new Parameter(0, Type::tvoid->pointerTo(), NULL, NULL, NULL));
+                            params->push(new Parameter(STCin, Type::tsize_t, NULL, NULL, NULL));
                             Parameters* dgparams = new Parameters;
-                            dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
+                            dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL, NULL));
                             if (dim == 2)
-                                dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
+                                dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL, NULL));
                             fldeTy[i] = new TypeDelegate(new TypeFunction(ParameterList(dgparams),
                                                                           Type::tint32, LINKd));
-                            params->push(new Parameter(0, fldeTy[i], NULL, NULL));
+                            params->push(new Parameter(0, fldeTy[i], NULL, NULL, NULL));
                             fdapply[i] = FuncDeclaration::genCfunc(params, Type::tint32, name[i]);
                         }
 
@@ -1637,14 +1637,14 @@ public:
                         FuncDeclaration *fdapply;
                         TypeDelegate *dgty;
                         params = new Parameters();
-                        params->push(new Parameter(STCin, tn->arrayOf(), NULL, NULL));
+                        params->push(new Parameter(STCin, tn->arrayOf(), NULL, NULL, NULL));
                         Parameters* dgparams = new Parameters;
-                        dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
+                        dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL, NULL));
                         if (dim == 2)
-                            dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
+                            dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL, NULL));
                         dgty = new TypeDelegate(new TypeFunction(ParameterList(dgparams),
                                                                  Type::tint32, LINKd));
-                        params->push(new Parameter(0, dgty, NULL, NULL));
+                        params->push(new Parameter(0, dgty, NULL, NULL, NULL));
                         fdapply = FuncDeclaration::genCfunc(params, Type::tint32, fdname);
 
                         if (tab->ty == Tsarray)
@@ -3192,7 +3192,7 @@ public:
             cs->push(new ExpStatement(ss->loc, tmp));
 
             Parameters* args = new Parameters;
-            args->push(new Parameter(0, ClassDeclaration::object->type, NULL, NULL));
+            args->push(new Parameter(0, ClassDeclaration::object->type, NULL, NULL, NULL));
 
             FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorenter);
             Expression *e = new CallExp(ss->loc, new VarExp(ss->loc, fdenter, false), new VarExp(ss->loc, tmp));
@@ -3234,7 +3234,7 @@ public:
             cs->push(new ExpStatement(ss->loc, v));
 
             Parameters* args = new Parameters;
-            args->push(new Parameter(0, t->pointerTo(), NULL, NULL));
+            args->push(new Parameter(0, t->pointerTo(), NULL, NULL, NULL));
 
             FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalenter, STCnothrow);
             Expression *e = new AddrExp(ss->loc, tmpExp);
diff --git a/gcc/d/dmd/traits.c b/gcc/d/dmd/traits.c
index 658529943ea..2f00c883706 100644
--- a/gcc/d/dmd/traits.c
+++ b/gcc/d/dmd/traits.c
@@ -658,7 +658,8 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc)
     if (e->ident != Id::compiles &&
         e->ident != Id::isSame &&
         e->ident != Id::identifier &&
-        e->ident != Id::getProtection && e->ident != Id::getVisibility)
+        e->ident != Id::getProtection && e->ident != Id::getVisibility &&
+        e->ident != Id::getAttributes)
     {
         // Pretend we're in a deprecated scope so that deprecation messages
         // aren't triggered when checking if a symbol is deprecated
@@ -905,8 +906,12 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc)
         Identifier *id = NULL;
         if (Parameter *po = isParameter(o))
         {
+            if (!po->ident)
+            {
+                e->error("argument `%s` has no identifier", po->type->toChars());
+                return new ErrorExp();
+            }
             id = po->ident;
-            assert(id);
         }
         else
         {
@@ -1245,23 +1250,39 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc)
     }
     else if (e->ident == Id::getAttributes)
     {
+        /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
+         * a symbol should not be folded to a constant.
+         * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
+         */
+        if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 3))
+            return new ErrorExp();
+
         if (dim != 1)
             return dimError(e, 1, dim);
 
         RootObject *o = (*e->args)[0];
+        Parameter *po = isParameter(o);
         Dsymbol *s = getDsymbolWithoutExpCtx(o);
-        if (!s)
+        UserAttributeDeclaration *udad = NULL;
+        if (po)
         {
-            e->error("first argument is not a symbol");
-            return new ErrorExp();
+            udad = po->userAttribDecl;
         }
-        if (Import *imp = s->isImport())
+        else if (s)
         {
-            s = imp->mod;
+            if (Import *imp = s->isImport())
+            {
+                s = imp->mod;
+            }
+            //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->_scope);
+            udad = s->userAttribDecl;
+        }
+        else
+        {
+            e->error("first argument is not a symbol");
+            return new ErrorExp();
         }
 
-        //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->_scope);
-        UserAttributeDeclaration *udad = s->userAttribDecl;
         Expressions *exps = udad ? udad->getAttributes() : new Expressions();
         TupleExp *tup = new TupleExp(e->loc, exps);
         return semantic(tup, sc);
diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/header1.d b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d
index a746a2aac06..d8221eb882a 100644
--- a/gcc/testsuite/gdc.test/compilable/extra-files/header1.d
+++ b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d
@@ -519,3 +519,21 @@ struct Foo3A(T)
     @disable this(this);
     @disable this();
 }
+
+void test13x(@(10) int a, @(20) int, @(30) @(40) int[] arr...) {}
+
+enum Test14UDA1;
+struct Test14UDA2
+{
+    string str;
+}
+
+Test14UDA2 test14uda3(string name)
+{
+    return Test14UDA2(name);
+}
+struct Test14UDA4(string v){}
+
+void test14x(@Test14UDA1 int, @Test14UDA2("1") int, @test14uda3("2") int, @Test14UDA4!"3" int) {}
+
+void test15x(@(20) void delegate(int) @safe dg){}
diff --git a/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d b/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d
index 1a7d6506669..5ee94868993 100644
--- a/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d
+++ b/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d
@@ -11,3 +11,5 @@ struct UDA
 }
 
 void main() {}
+
+void foo(@(1) int bar, @UDA(2) string bebe);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10207.d b/gcc/testsuite/gdc.test/fail_compilation/fail10207.d
index ac8b4eef11a..3f09a27541a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10207.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10207.d
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail10207.d(7): Error: user defined attributes not allowed for `alias` declarations
+fail_compilation/fail10207.d(7): Error: user-defined attributes not allowed for `alias` declarations
 ---
 */
 alias @Safe int __externC;
diff --git a/gcc/testsuite/gdc.test/runnable/uda.d b/gcc/testsuite/gdc.test/runnable/uda.d
index c1782c90a7b..38f84e5971d 100644
--- a/gcc/testsuite/gdc.test/runnable/uda.d
+++ b/gcc/testsuite/gdc.test/runnable/uda.d
@@ -467,6 +467,193 @@ static assert(__traits(getAttributes, FileData11844.member)[0](new FileData11844
 
 /************************************************/
 
+template AliasSeq(T...)
+{
+    alias AliasSeq = T;
+}
+
+template ParameterUDA(size_t p_num, func...)
+if (func.length == 1 && is(typeof(func[0]) PT == __parameters) && PT.length > p_num)
+{
+    static if (is(typeof(func[0]) PT == __parameters))
+    {
+        template Get(size_t i)
+        {
+            static if (//!isFunctionPointer!func && !isDelegate!func
+                       // Parameters without UDA may yield CT error.
+                       /*&&*/ is(typeof(__traits(getAttributes, PT[i..i+1]))x))
+            {
+                alias Get = AliasSeq!(__traits(getAttributes, PT[i..i+1]));
+            }
+            else
+            {
+                alias Get = AliasSeq!();
+            }
+        }
+    }
+    else
+    {
+        static assert(0, func[0].stringof ~ "is not a function");
+
+        // Define dummy entities to avoid pointless errors
+        template Get(size_t i) { alias Get = AliasSeq!(); }
+        alias PT = AliasSeq!();
+    }
+
+    alias ParameterUDA = Get!p_num;
+}
+
+void test13x(@(10) int a, @(20) int, @(30) @(40) int[] arr...) {}
+
+void test13()
+{
+    static assert([ParameterUDA!(0, test13x)] == [10]);
+    static assert([ParameterUDA!(1, test13x)] == [20]);
+    static assert([ParameterUDA!(2, test13x)] == [30, 40]);
+}
+
+template Test13t(F)
+{
+    static assert(!__traits(compiles, ParameterUDA!(0, F)));
+    static assert(!__traits(compiles, ParameterUDA!(1, F)));
+    static assert(!__traits(compiles, ParameterUDA!(2, F)));
+    enum Test13t = true;
+}
+
+alias test13t = Test13t!(typeof(test13x));
+
+enum Test14UDA1;
+
+struct Test14UDA2
+{
+    string str;
+}
+
+Test14UDA2 test14uda3(string name)
+{
+    return Test14UDA2(name);
+}
+
+struct Test14UDA4(string v)
+{
+}
+
+void test14x(@Test14UDA1 int, @Test14UDA2("1") int, @test14uda3("2") int, @Test14UDA4!"3" int) {}
+void test14()
+{
+    static assert(is(ParameterUDA!(0, test14x)[0] == Test14UDA1));
+    static assert(ParameterUDA!(1, test14x)[0] == Test14UDA2("1"));
+    static assert(ParameterUDA!(2, test14x)[0] == test14uda3("2"));
+    static assert(is(ParameterUDA!(3, test14x)[0] == Test14UDA4!"3"));
+}
+
+void test15x(@(20) void delegate(int) @safe dg)
+{
+    static assert([__traits(getAttributes, dg)] == [20]);
+    static assert(is(typeof(dg) == void delegate(int) @safe));
+}
+
+template MinimalFunctionTypeOf(func...)
+if (func.length == 1)
+{
+    static if (is(func[0] T) || is(typeof(func[0]) T) && is(T Fdlg == delegate))
+        alias MinimalFunctionTypeOf = Fdlg; // HIT: delegate
+    else
+        static assert(0);
+}
+
+template Parameters(func...)
+if (func.length == 1)
+{
+    static if (is(MinimalFunctionTypeOf!func P == function))
+        alias Parameters = P;
+    else
+        static assert(0, "argument has no parameters");
+}
+
+void test15y(@(20) void delegate(@Test14UDA2("2") @("test15yUDA") int) @safe dg)
+{
+    static assert([__traits(getAttributes, dg)] == [20]);
+    static assert(is(typeof(dg) == void delegate(int) @safe));
+    auto foo = (@("myUDA") int x){
+        static assert([__traits(getAttributes, x)] == ["myUDA"]);
+    };
+    static assert(__traits(getAttributes, Parameters!dg)[0] == Test14UDA2("2"));
+    static assert(__traits(getAttributes, Parameters!dg)[1] == "test15yUDA");
+}
+
+void test15z()
+{
+    test15y((@(15) @(16) int x){
+        static assert([__traits(getAttributes, x)] == [15, 16]);
+    });
+}
+
+void test16x(A)(@(22) A a)
+{
+    static assert([__traits(getAttributes, a)] == [22]);
+}
+
+void test16()
+{
+    static assert([ParameterUDA!(0, test16x!int)] == [22]);
+}
+
+void test17()
+{
+    void test17x(A)(@(23) A a)
+    {
+        static assert([__traits(getAttributes, a)] == [23]);
+    }
+    static assert([ParameterUDA!(0, test17x!int)] == [23]);
+}
+
+void test18()
+{
+    void test18a(@(Tuple!(18, "a")) int a)
+    {
+        static assert(__traits(getAttributes, a) == Tuple!(18, "a"));
+    }
+    void test18b(@Tuple!(18, "b") int a)
+    {
+        static assert(__traits(getAttributes, a) == Tuple!(18, "b"));
+    }
+
+    static assert(ParameterUDA!(0, test18a) == Tuple!(18, "a"));
+    static assert(ParameterUDA!(0, test18b) == Tuple!(18, "b"));
+}
+
+// Lambdas with parentheses:
+void test19()
+{
+    // lambdas without parentheses
+    alias test19a = @(3) b => 1 + 2;
+    alias test19b = @(3) @(4) b => 1 + 2;
+
+    alias test19c = (@(3) c, @(5) d) => 1 + 2;
+    alias test19d = (@(3) @(4) c, @(5) d) => 1 + 2;
+    auto test19e = (@(3) int c, @(5) int d) => 1 + 2;
+
+    // still allow alias function declarations
+    alias FuncType = @safe void function();
+    alias FuncType2 = @safe nothrow void function();
+    alias FuncType3 = nothrow void function();
+    alias FuncType4 = nothrow @safe void function();
+}
+
+void test20()
+{
+    // Using a delegate with inferred parameter type
+    void test20a(int delegate(int) t){ t(1); }
+    test20a((@(19) a) {
+        static assert([__traits(getAttributes, a)] == [19]);
+        return a + 2;
+    });
+}
+
+/************************************************/
+
+
 int main()
 {
     test1();
@@ -482,6 +669,13 @@ int main()
     test11();
     test12();
     test9178();
+    test13();
+    test14();
+    test16();
+    test17();
+    test18();
+    test19();
+    test20();
 
     printf("Success\n");
     return 0;
