Support the tls_model attribute (PR9788)

This adds support for the tls_model attribute. This allows the user to
choose a TLS model that is better than what LLVM would select by
default. For example, a variable might be declared as:

  __thread int x __attribute__((tls_model("initial-exec")));

if it will not be used in a shared library that is dlopen'ed.

This depends on LLVM r159077.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159078 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index b443911..744d18b 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -43,7 +43,8 @@
   ExpectedMethod,
   ExpectedVariableFunctionOrLabel,
   ExpectedFieldOrGlobalVar,
-  ExpectedStruct
+  ExpectedStruct,
+  ExpectedTLSVar
 };
 
 //===----------------------------------------------------------------------===//
@@ -1440,6 +1441,42 @@
   D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getRange(), S.Context));
 }
 
+static void handleTLSModelAttr(Sema &S, Decl *D,
+                               const AttributeList &Attr) {
+  // Check the attribute arguments.
+  if (Attr.getNumArgs() != 1) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+    return;
+  }
+
+  Expr *Arg = Attr.getArg(0);
+  Arg = Arg->IgnoreParenCasts();
+  StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
+
+  // Check that it is a string.
+  if (!Str) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_not_string) << "tls_model";
+    return;
+  }
+
+  if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->isThreadSpecified()) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedTLSVar;
+    return;
+  }
+
+  // Check that the value.
+  StringRef Model = Str->getString();
+  if (Model != "global-dynamic" && Model != "local-dynamic"
+      && Model != "initial-exec" && Model != "local-exec") {
+    S.Diag(Attr.getLoc(), diag::err_attr_tlsmodel_arg);
+    return;
+  }
+
+  D->addAttr(::new (S.Context) TLSModelAttr(Attr.getRange(), S.Context,
+                                            Model));
+}
+
 static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   // Check the attribute arguments.
   if (Attr.hasParameterOrArguments()) {
@@ -3939,6 +3976,7 @@
     handleAlwaysInlineAttr  (S, D, Attr); break;
   case AttributeList::AT_AnalyzerNoReturn:
     handleAnalyzerNoReturnAttr  (S, D, Attr); break;
+  case AttributeList::AT_TLSModel:    handleTLSModelAttr    (S, D, Attr); break;
   case AttributeList::AT_Annotate:    handleAnnotateAttr    (S, D, Attr); break;
   case AttributeList::AT_Availability:handleAvailabilityAttr(S, D, Attr); break;
   case AttributeList::AT_CarriesDependency: