Add a bunch of attributes, patch by Nuno Lopes.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@47837 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp
index 2652848..6854aac 100644
--- a/Sema/SemaDecl.cpp
+++ b/Sema/SemaDecl.cpp
@@ -242,6 +242,33 @@
   return New;
 }
 
+/// DeclhasAttr - returns true if decl Declaration already has the target attribute.
+static bool DeclHasAttr(const Decl *decl, const Attr *target) {
+  for (const Attr *attr = decl->getAttrs(); attr; attr = attr->getNext())
+    if (attr->getKind() == target->getKind())
+      return true;
+
+  return false;
+}
+
+/// MergeAttributes - append attributes from the Old decl to the New one.
+static void MergeAttributes(Decl *New, Decl *Old) {
+  Attr *attr = const_cast<Attr*>(Old->getAttrs()), *tmp;
+
+// FIXME: fix this code to cleanup the Old attrs correctly
+  while (attr) {
+     tmp = attr;
+     attr = attr->getNext();
+
+    if (!DeclHasAttr(New, tmp)) {
+       New->addAttr(tmp);
+    } else {
+       tmp->setNext(0);
+       delete(tmp);
+    }
+  }
+}
+
 /// MergeFunctionDecl - We just parsed a function 'New' which has the same name
 /// and scope as a previous declaration 'Old'.  Figure out how to resolve this
 /// situation, merging decls or emitting diagnostics as appropriate.
@@ -256,7 +283,8 @@
     return New;
   }
 
-  // FIXME: propagate old Attrs to the New decl
+  MergeAttributes(New, Old);
+
   
   QualType OldQType = Old->getCanonicalType();
   QualType NewQType = New->getCanonicalType();
@@ -326,6 +354,9 @@
     Diag(OldD->getLocation(), diag::err_previous_definition);
     return New;
   }
+
+  MergeAttributes(New, Old);
+
   // Verify the types match.
   if (Old->getCanonicalType() != New->getCanonicalType() && 
       !areEquivalentArrayTypes(New->getCanonicalType(), Old->getCanonicalType())) {
@@ -1781,7 +1812,22 @@
     }
     break;
   case AttributeList::AT_deprecated:
-    New->addAttr(new DeprecatedAttr());
+    HandleDeprecatedAttribute(New, Attr);
+    break;
+  case AttributeList::AT_visibility:
+    HandleVisibilityAttribute(New, Attr);
+    break;
+  case AttributeList::AT_weak:
+    HandleWeakAttribute(New, Attr);
+    break;
+  case AttributeList::AT_dllimport:
+    HandleDLLImportAttribute(New, Attr);
+    break;
+  case AttributeList::AT_dllexport:
+    HandleDLLExportAttribute(New, Attr);
+    break;
+  case AttributeList::AT_nothrow:
+    HandleNothrowAttribute(New, Attr);
     break;
   case AttributeList::AT_aligned:
     HandleAlignedAttribute(New, Attr);
@@ -1795,6 +1841,9 @@
   case AttributeList::AT_noreturn:
     HandleNoReturnAttribute(New, Attr);
     break;
+  case AttributeList::AT_format:
+    HandleFormatAttribute(New, Attr);
+    break;
   default:
 #if 0
     // TODO: when we have the full set of attributes, warn about unknown ones.
@@ -1952,6 +2001,177 @@
   d->addAttr(new NoReturnAttr());
 }
 
+void Sema::HandleDeprecatedAttribute(Decl *d, AttributeList *rawAttr) {
+  // check the attribute arguments.
+  if (rawAttr->getNumArgs() != 0) {
+    Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+         std::string("0"));
+    return;
+  }
+
+  d->addAttr(new DeprecatedAttr());
+}
+
+void Sema::HandleVisibilityAttribute(Decl *d, AttributeList *rawAttr) {
+  // check the attribute arguments.
+  if (rawAttr->getNumArgs() != 0) {
+    Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+         std::string("1"));
+    return;
+  }
+
+  if (!rawAttr->getParameterName()) {
+    Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string,
+           "visibility", std::string("1"));
+    return;
+  }
+
+  const char *typeStr = rawAttr->getParameterName()->getName();
+  llvm::GlobalValue::VisibilityTypes type;
+
+  if (!memcmp(typeStr, "default", 7))
+    type = llvm::GlobalValue::DefaultVisibility;
+  else if (!memcmp(typeStr, "hidden", 6))
+    type = llvm::GlobalValue::HiddenVisibility;
+  else if (!memcmp(typeStr, "internal", 8))
+    type = llvm::GlobalValue::HiddenVisibility; // FIXME
+  else if (!memcmp(typeStr, "protected", 9))
+    type = llvm::GlobalValue::ProtectedVisibility;
+  else {
+    Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported,
+           "visibility", typeStr);
+    return;
+  }
+
+  d->addAttr(new VisibilityAttr(type));
+}
+
+void Sema::HandleWeakAttribute(Decl *d, AttributeList *rawAttr) {
+  // check the attribute arguments.
+  if (rawAttr->getNumArgs() != 0) {
+    Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+         std::string("0"));
+    return;
+  }
+
+  d->addAttr(new WeakAttr());
+}
+
+void Sema::HandleDLLImportAttribute(Decl *d, AttributeList *rawAttr) {
+  // check the attribute arguments.
+  if (rawAttr->getNumArgs() != 0) {
+    Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+         std::string("0"));
+    return;
+  }
+
+  d->addAttr(new DLLImportAttr());
+}
+
+void Sema::HandleDLLExportAttribute(Decl *d, AttributeList *rawAttr) {
+  // check the attribute arguments.
+  if (rawAttr->getNumArgs() != 0) {
+    Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+         std::string("0"));
+    return;
+  }
+
+  d->addAttr(new DLLExportAttr());
+}
+
+void Sema::HandleNothrowAttribute(Decl *d, AttributeList *rawAttr) {
+  // check the attribute arguments.
+  if (rawAttr->getNumArgs() != 0) {
+    Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+         std::string("0"));
+    return;
+  }
+
+  d->addAttr(new NoThrowAttr());
+}
+
+void Sema::HandleFormatAttribute(Decl *d, AttributeList *rawAttr) {
+
+  if (!rawAttr->getParameterName()) {
+    Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string,
+           "format", std::string("1"));
+    return;
+  }
+
+  if (rawAttr->getNumArgs() != 2) {
+    Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+         std::string("3"));
+    return;
+  }
+
+  FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
+  if (!Fn) {
+    Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type,
+           "format", "function");
+    return;
+  }
+
+  // FIXME: in C++ the implicit 'this' function parameter also counts.
+  // the index must start in 1 and the limit is numargs+1
+  unsigned NumArgs = Fn->getNumParams()+1; // +1 for ...
+
+  const char *Format = rawAttr->getParameterName()->getName();
+  unsigned FormatLen = rawAttr->getParameterName()->getLength();
+
+  // Normalize the argument, __foo__ becomes foo.
+  if (FormatLen > 4 && Format[0] == '_' && Format[1] == '_' &&
+      Format[FormatLen - 2] == '_' && Format[FormatLen - 1] == '_') {
+    Format += 2;
+    FormatLen -= 4;
+  }
+
+  if (!((FormatLen == 5 && !memcmp(Format, "scanf", 5))
+     || (FormatLen == 6 && !memcmp(Format, "printf", 6))
+     || (FormatLen == 7 && !memcmp(Format, "strfmon", 7))
+     || (FormatLen == 8 && !memcmp(Format, "strftime", 8)))) {
+    Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported,
+           "format", rawAttr->getParameterName()->getName());
+    return;
+  }
+
+  Expr *IdxExpr = static_cast<Expr *>(rawAttr->getArg(0));
+  llvm::APSInt Idx(32);
+  if (!IdxExpr->isIntegerConstantExpr(Idx, Context)) {
+    Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_int,
+           "format", std::string("2"), IdxExpr->getSourceRange());
+    return;
+  }
+
+  if (Idx.getZExtValue() < 1 || Idx.getZExtValue() > NumArgs) {
+    Diag(rawAttr->getLoc(), diag::err_attribute_argument_out_of_bounds,
+           "format", std::string("2"), IdxExpr->getSourceRange());
+    return;
+  }
+
+  Expr *FirstArgExpr = static_cast<Expr *>(rawAttr->getArg(1));
+  llvm::APSInt FirstArg(32);
+  if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, Context)) {
+    Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_int,
+           "format", std::string("3"), FirstArgExpr->getSourceRange());
+    return;
+  }
+
+  if (FormatLen == 8 && !memcmp(Format, "strftime", 8)) {
+    if (FirstArg.getZExtValue() != 0) {
+      Diag(rawAttr->getLoc(), diag::err_format_strftime_third_parameter,
+             FirstArgExpr->getSourceRange());
+      return;
+    }
+  } else if (FirstArg.getZExtValue() > NumArgs) {
+    Diag(rawAttr->getLoc(), diag::err_attribute_argument_out_of_bounds,
+           "format", std::string("3"), FirstArgExpr->getSourceRange());
+    return;
+  }
+
+  d->addAttr(new FormatAttr(std::string(Format, FormatLen),
+                            Idx.getZExtValue(), FirstArg.getZExtValue()));
+}
+
 void Sema::HandleAnnotateAttribute(Decl *d, AttributeList *rawAttr) {
   // check the attribute arguments.
   if (rawAttr->getNumArgs() != 1) {