diff --git a/clang/include/clang/3C/Utils.h b/clang/include/clang/3C/Utils.h
index b14041381605..f14891370686 100644
--- a/clang/include/clang/3C/Utils.h
+++ b/clang/include/clang/3C/Utils.h
@@ -103,6 +103,11 @@ getCheckedPointerKind(clang::InteropTypeExpr *ItypeExpr);
 
 std::string getStorageQualifierString(clang::Decl *D);
 
+void forEachAttribute(clang::Decl *D,
+                      llvm::function_ref<void(const clang::Attr *A)> F);
+
+std::string getAttributeString(clang::Decl *D);
+
 std::error_code tryGetCanonicalFilePath(const std::string &FileName,
                                         std::string &AbsoluteFp);
 
diff --git a/clang/lib/3C/DeclRewriter.cpp b/clang/lib/3C/DeclRewriter.cpp
index 72ae4289df83..99b49111c4d7 100644
--- a/clang/lib/3C/DeclRewriter.cpp
+++ b/clang/lib/3C/DeclRewriter.cpp
@@ -188,7 +188,8 @@ void DeclRewriter::rewriteDecls(ASTContext &Context, ProgramInfo &Info,
         if (VDLToStmtMap.find(D) != VDLToStmtMap.end())
           DS = VDLToStmtMap[D];
 
-        std::string NewTy = getStorageQualifierString(D);
+        std::string NewTy =
+          getAttributeString(D) + getStorageQualifierString(D);
         bool IsExternGlobalVar =
           isa<VarDecl>(D) &&
           cast<VarDecl>(D)->getFormalLinkage() == Linkage::ExternalLinkage;
@@ -625,7 +626,8 @@ bool FunctionDeclBuilder::VisitFunctionDecl(FunctionDecl *FD) {
       this->buildDeclVar(CV, PVDecl, Type, IType,
                          PVDecl->getQualifiedNameAsString(), RewriteGeneric,
                          RewriteParams, RewriteReturn, FD->isStatic());
-      ParmStrs.push_back(Type + IType);
+      std::string AttrStr = getAttributeString(PVDecl);
+      ParmStrs.push_back(AttrStr + Type + IType);
       ProtoHasItype |= !IType.empty();
     }
   } else if (FDConstraint->numParams() != 0) {
@@ -704,6 +706,14 @@ bool FunctionDeclBuilder::VisitFunctionDecl(FunctionDecl *FD) {
     RewriteReturn = true;
   }
 
+
+  std::string AttrStr = getAttributeString(FD);
+  if ((RewriteReturn || RewriteParams) && !AttrStr.empty()) {
+    ReturnVar = AttrStr + ReturnVar;
+    RewriteParams = true;
+    RewriteReturn = true;
+  }
+
   // Mirrors the check above that sets RewriteGeneric to true.
   // If we've decided against making this generic, remove the generic params
   // so later rewrites (of typeparams) don't happen
diff --git a/clang/lib/3C/RewriteUtils.cpp b/clang/lib/3C/RewriteUtils.cpp
index 31bbc31e0422..9770e77c68e7 100644
--- a/clang/lib/3C/RewriteUtils.cpp
+++ b/clang/lib/3C/RewriteUtils.cpp
@@ -521,6 +521,23 @@ SourceLocation FunctionDeclReplacement::getDeclEnd(SourceManager &SM) const {
       (!End.isValid() || SM.isBeforeInTranslationUnit(End, AnnotationsEnd)))
     End = AnnotationsEnd;
 
+  // Functions attributes can appear after the the closing paren for the
+  // parameter list.
+  forEachAttribute(Decl, [&End, &SM, this](const clang::Attr *A) {
+    SourceLocation AttrEnd = A->getRange().getEnd();
+
+    llvm::Optional<Token> NextTok = Lexer::findNextToken(AttrEnd, SM,
+                                                         Decl->getLangOpts());
+
+    SourceLocation NewEnd = NextTok.hasValue() ? NextTok->getEndLoc()
+                                               : A->getRange().getEnd();
+    NewEnd = SM.getExpansionLoc(NewEnd);
+
+    if (!End.isValid() ||
+        (NewEnd.isValid() && SM.isBeforeInTranslationUnit(End, NewEnd)))
+      End = NewEnd;
+  });
+
   // SourceLocations are weird and turn up invalid for reasons I don't
   // understand. Fallback to extracting r paren location from source
   // character buffer.
diff --git a/clang/lib/3C/Utils.cpp b/clang/lib/3C/Utils.cpp
index 84ede9a2f98e..49f7e238e475 100644
--- a/clang/lib/3C/Utils.cpp
+++ b/clang/lib/3C/Utils.cpp
@@ -15,6 +15,7 @@
 #include "clang/Sema/Sema.h"
 #include "llvm/Support/Path.h"
 #include <errno.h>
+#include <sstream>
 
 using namespace llvm;
 using namespace clang;
@@ -131,6 +132,39 @@ std::string getStorageQualifierString(Decl *D) {
   return "";
 }
 
+void forEachAttribute(Decl *D, llvm::function_ref<void(const Attr *)> F) {
+  std::ostringstream AttrStr;
+  if (D->hasAttrs())
+    for (auto *A : D->getAttrs())
+      F(A);
+  if (auto *FD = dyn_cast<DeclaratorDecl>(D)) {
+    if (auto *TSInfo = FD->getTypeSourceInfo()) {
+      auto ATLoc = getBaseTypeLoc(
+        TSInfo->getTypeLoc()).getAs<AttributedTypeLoc>();
+      if (!ATLoc.isNull())
+        F(ATLoc.getAttr());
+    }
+  }
+}
+
+std::string getAttributeString(Decl *D) {
+  std::string AttrStr;
+  llvm::raw_string_ostream AttrStream(AttrStr);
+  forEachAttribute(D, [&AttrStream, D](const clang::Attr *A) {
+    A->printPretty(AttrStream, PrintingPolicy(D->getLangOpts()));
+  });
+  AttrStream.flush();
+
+  // Attr::printPretty puts a space before each attribute resulting in a space
+  // appearing before any attributes, and no space following the attributes.
+  // I need this to be the other way around.
+  if (!AttrStr.empty()) {
+    assert(AttrStr[0] == ' ');
+    return AttrStr.substr(1) + ' ';
+  }
+  return AttrStr;
+}
+
 bool isNULLExpression(clang::Expr *E, ASTContext &C) {
   QualType Typ = E->getType();
   E = removeAuxillaryCasts(E);
@@ -331,7 +365,6 @@ static bool castCheck(clang::QualType DstType, clang::QualType SrcType) {
   if (SrcPtrTypePtr || DstPtrTypePtr)
     return false;
 
-  // Check function cast by comparing parameter and return types individually.
   const auto *SrcFnType = dyn_cast<clang::FunctionProtoType>(SrcTypePtr);
   const auto *DstFnType = dyn_cast<clang::FunctionProtoType>(DstTypePtr);
   if (SrcFnType && DstFnType) {
@@ -459,6 +492,7 @@ TypeLoc getBaseTypeLoc(TypeLoc T) {
   assert(!T.isNull() && "Can't get base location from Null.");
   while (!T.getNextTypeLoc().isNull() &&
          (!T.getAs<ParenTypeLoc>().isNull() ||
+          !T.getAs<MacroQualifiedTypeLoc>().isNull() ||
           T.getTypePtr()->isPointerType() || T.getTypePtr()->isArrayType()))
     T = T.getNextTypeLoc();
   return T;
diff --git a/clang/test/3C/attr.c b/clang/test/3C/attr.c
new file mode 100644
index 000000000000..6deccc30a9e0
--- /dev/null
+++ b/clang/test/3C/attr.c
@@ -0,0 +1,93 @@
+// RUN: rm -rf %t*
+// RUN: 3c -base-dir=%S -alltypes -addcr %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_ALL","CHECK" %s
+// RUN: 3c -base-dir=%S -addcr %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_NOALL","CHECK" %s
+// RUN: 3c -base-dir=%S -addcr %s -- | %clang -c -fcheckedc-extension -x c -o /dev/null -
+// RUN: 3c -base-dir=%S -output-dir=%t.checked -alltypes %s --
+// RUN: 3c -base-dir=%t.checked -alltypes %t.checked/attr.c -- | diff %t.checked/attr.c -
+
+// function attributes
+
+__attribute__((disable_tail_calls))
+int *a() {
+//CHECK: __attribute__((disable_tail_calls)) _Ptr<int> a(void) _Checked {
+  return 0;
+}
+
+__attribute__((disable_tail_calls))
+void b(int *x) {
+//CHECK: __attribute__((disable_tail_calls)) void b(_Ptr<int> x) _Checked {
+  return;
+}
+
+__attribute__((disable_tail_calls))
+int *c(int *x) {
+//CHECK: __attribute__((disable_tail_calls)) _Ptr<int> c(_Ptr<int> x) _Checked {
+  return 0;
+}
+int *e(int *x)
+__attribute__((disable_tail_calls))
+//CHECK: __attribute__((disable_tail_calls)) int *e(_Ptr<int> x) : itype(_Ptr<int>)
+{
+  return 1;
+}
+
+__attribute__((no_stack_protector))
+int *f(int *x)
+__attribute__((disable_tail_calls))
+//CHECK: __attribute__((no_stack_protector)) __attribute__((disable_tail_calls)) _Ptr<int> f(_Ptr<int> x)
+{
+//CHECK: _Checked {
+  while (1){}
+}
+
+// variable attribute on param
+
+void g(__attribute__((noescape)) int *x) {
+//CHECK: void g(__attribute__((noescape)) _Ptr<int> x) _Checked {
+  return;
+}
+
+void h(__attribute__((noescape)) int *x) {
+//CHECK: void h(__attribute__((noescape)) int *x : itype(_Ptr<int>)) {
+  x = 1;
+}
+
+int *i(__attribute__((noescape)) void *x) {
+//CHECK: _For_any(T) _Ptr<int> i(__attribute__((noescape)) _Ptr<T> x) {
+  return 0;
+}
+
+// variable attribute on local
+
+void j() {
+  __attribute__((nodebug)) int *a;
+  __attribute__((nodebug)) int *b = 0;
+  __attribute__((nodebug)) int *c = 1;
+
+  __attribute__((nodebug)) int *d, *e = 1, **f, g, *h;
+//CHECK: __attribute__((nodebug)) _Ptr<int> a = ((void *)0);
+//CHECK: __attribute__((nodebug)) _Ptr<int> b = 0;
+//CHECK: __attribute__((nodebug)) int *c = 1;
+//CHECK: __attribute__((nodebug)) _Ptr<int> d = ((void *)0);
+//CHECK: int *e __attribute__((nodebug)) = 1;
+//CHECK: __attribute__((nodebug)) _Ptr<_Ptr<int>> f = ((void *)0);
+//CHECK: int g __attribute__((nodebug));
+//CHECK: __attribute__((nodebug)) _Ptr<int> h = ((void *)0);
+}
+
+#define FOO __attribute__((ms_abi))
+int *foo()  FOO ;
+int *foo() { return 0; }
+//CHECK: __attribute__((ms_abi)) _Ptr<int> foo(void) ;
+//CHECK: _Ptr<int> foo(void) _Checked { return 0; }
+
+// Attribute parameter is preserved
+__attribute__((deprecated("bar"))) int *bar();
+int *bar() { return 0; }
+//CHECK: __attribute__((deprecated("bar"))) _Ptr<int> bar(void);
+//CHECK: __attribute__((deprecated("bar"))) _Ptr<int> bar(void) _Checked { return 0; }
+
+// Because toupper is a standard libary function, it has attributes in the AST
+// even though there are none in the source. This was causing issues when
+// trying to get the name of the attribute.
+int toupper(int c) { return 0; }
diff --git a/clang/test/3C/valist.c b/clang/test/3C/valist.c
index 8283d3ba2d1e..f9bce1c74056 100644
--- a/clang/test/3C/valist.c
+++ b/clang/test/3C/valist.c
@@ -51,3 +51,16 @@ typedef void fuz(va_list, int *);
 /*force output*/
 int *p;
 //CHECK: _Ptr<int> p = ((void *)0);
+
+// This tests va_list correctness using windows builtins
+void ms_test_foo( const char *fmt, __builtin_ms_va_list argp);
+__attribute__((ms_abi)) int *ms_test_bar(const char *fmt, ...)  {
+//CHECK: __attribute__((ms_abi)) _Ptr<int> ms_test_bar(const char *fmt : itype(_Ptr<const char>), ...)  {
+  __builtin_ms_va_list argp;
+  __builtin_ms_va_start(argp, fmt);
+  //CHECK: __builtin_ms_va_start(argp, fmt);
+  ms_test_foo(fmt, argp);
+  __builtin_ms_va_end(argp);
+  //CHECK: __builtin_ms_va_end(argp);
+  return 0;
+}