Keep track of the actual storage specifier written on a variable or
function declaration, since it may end up being changed (e.g.,
"extern" can become "static" if a prior declaration was static). Patch
by Enea Zaffanella and Paolo Bolzoni.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101826 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index e057a92..a95d082 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -810,7 +810,8 @@
                               TypeSourceInfo *TSInfo, QualType T,
                               IdentifierInfo *Name,
                               SourceLocation NameLoc,
-                              VarDecl::StorageClass StorageClass);
+                              VarDecl::StorageClass StorageClass,
+                              VarDecl::StorageClass StorageClassAsWritten);
   virtual void ActOnObjCCatchParam(DeclPtrTy D);
   virtual void ActOnParamDefaultArgument(DeclPtrTy param,
                                          SourceLocation EqualLoc,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 115b7bf..9ef0359 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -717,7 +717,8 @@
   FunctionDecl *New = FunctionDecl::Create(Context,
                                            Context.getTranslationUnitDecl(),
                                            Loc, II, R, /*TInfo=*/0,
-                                           FunctionDecl::Extern, false,
+                                           FunctionDecl::Extern,
+                                           FunctionDecl::None, false,
                                            /*hasPrototype=*/true);
   New->setImplicit();
 
@@ -728,7 +729,7 @@
     for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i)
       Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0,
                                            FT->getArgType(i), /*TInfo=*/0,
-                                           VarDecl::None, 0));
+                                           VarDecl::None, VarDecl::None, 0));
     New->setParams(Params.data(), Params.size());
   }
 
@@ -1160,7 +1161,8 @@
         ParmVarDecl *Param = ParmVarDecl::Create(Context, New,
                                                  SourceLocation(), 0,
                                                  *ParamType, /*TInfo=*/0,
-                                                 VarDecl::None, 0);
+                                                 VarDecl::None, VarDecl::None,
+                                                 0);
         Param->setImplicit();
         Params.push_back(Param);
       }
@@ -1592,6 +1594,44 @@
   return Invalid;
 }
 
+/// StorageClassSpecToVarDeclStorageClass - Maps a DeclSpec::SCS to
+/// a VarDecl::StorageClass. Any error reporting is up to the caller:
+/// illegal input values are mapped to VarDecl::None.
+static VarDecl::StorageClass
+StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec) {
+  switch (StorageClassSpec) {
+  case DeclSpec::SCS_unspecified:    return VarDecl::None;
+  case DeclSpec::SCS_extern:         return VarDecl::Extern;
+  case DeclSpec::SCS_static:         return VarDecl::Static;
+  case DeclSpec::SCS_auto:           return VarDecl::Auto;
+  case DeclSpec::SCS_register:       return VarDecl::Register;
+  case DeclSpec::SCS_private_extern: return VarDecl::PrivateExtern;
+    // Illegal SCSs map to None: error reporting is up to the caller.
+  case DeclSpec::SCS_mutable:        // Fall through.
+  case DeclSpec::SCS_typedef:        return VarDecl::None;
+  }
+  llvm_unreachable("unknown storage class specifier");
+}
+
+/// StorageClassSpecToFunctionDeclStorageClass - Maps a DeclSpec::SCS to
+/// a FunctionDecl::StorageClass. Any error reporting is up to the caller:
+/// illegal input values are mapped to FunctionDecl::None.
+static FunctionDecl::StorageClass
+StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec) {
+  switch (StorageClassSpec) {
+  case DeclSpec::SCS_unspecified:    return FunctionDecl::None;
+  case DeclSpec::SCS_extern:         return FunctionDecl::Extern;
+  case DeclSpec::SCS_static:         return FunctionDecl::Static;
+  case DeclSpec::SCS_private_extern: return FunctionDecl::PrivateExtern;
+    // Illegal SCSs map to None: error reporting is up to the caller.
+  case DeclSpec::SCS_auto:           // Fall through.
+  case DeclSpec::SCS_mutable:        // Fall through.
+  case DeclSpec::SCS_register:       // Fall through.
+  case DeclSpec::SCS_typedef:        return FunctionDecl::None;
+  }
+  llvm_unreachable("unknown storage class specifier");
+}
+
 /// ActOnAnonymousStructOrUnion - Handle the declaration of an
 /// anonymous structure or union. Anonymous unions are a C++ feature
 /// (C++ [class.union]) and a GNU C extension; anonymous structures
@@ -1712,29 +1752,25 @@
     if (getLangOptions().CPlusPlus)
       FieldCollector->Add(cast<FieldDecl>(Anon));
   } else {
-    VarDecl::StorageClass SC;
-    switch (DS.getStorageClassSpec()) {
-    default: assert(0 && "Unknown storage class!");
-    case DeclSpec::SCS_unspecified:    SC = VarDecl::None; break;
-    case DeclSpec::SCS_extern:         SC = VarDecl::Extern; break;
-    case DeclSpec::SCS_static:         SC = VarDecl::Static; break;
-    case DeclSpec::SCS_auto:           SC = VarDecl::Auto; break;
-    case DeclSpec::SCS_register:       SC = VarDecl::Register; break;
-    case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
-    case DeclSpec::SCS_mutable:
+    DeclSpec::SCS SCSpec = DS.getStorageClassSpec();
+    assert(SCSpec != DeclSpec::SCS_typedef &&
+           "Parser allowed 'typedef' as storage class VarDecl.");
+    VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec);
+    if (SCSpec == DeclSpec::SCS_mutable) {
       // mutable can only appear on non-static class members, so it's always
       // an error here
       Diag(Record->getLocation(), diag::err_mutable_nonmember);
       Invalid = true;
       SC = VarDecl::None;
-      break;
     }
+    SCSpec = DS.getStorageClassSpecAsWritten();
+    VarDecl::StorageClass SCAsWritten
+      = StorageClassSpecToVarDeclStorageClass(SCSpec);
 
     Anon = VarDecl::Create(Context, Owner, Record->getLocation(),
                            /*IdentifierInfo=*/0,
                            Context.getTypeDeclType(Record),
-                           TInfo,
-                           SC);
+                           TInfo, SC, SCAsWritten);
   }
   Anon->setImplicit();
 
@@ -2332,24 +2368,20 @@
   if (getLangOptions().CPlusPlus)
     CheckExtraCXXDefaultArguments(D);
 
-  VarDecl *NewVD;
-  VarDecl::StorageClass SC;
-  switch (D.getDeclSpec().getStorageClassSpec()) {
-  default: assert(0 && "Unknown storage class!");
-  case DeclSpec::SCS_unspecified:    SC = VarDecl::None; break;
-  case DeclSpec::SCS_extern:         SC = VarDecl::Extern; break;
-  case DeclSpec::SCS_static:         SC = VarDecl::Static; break;
-  case DeclSpec::SCS_auto:           SC = VarDecl::Auto; break;
-  case DeclSpec::SCS_register:       SC = VarDecl::Register; break;
-  case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
-  case DeclSpec::SCS_mutable:
+  DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
+  assert(SCSpec != DeclSpec::SCS_typedef &&
+         "Parser allowed 'typedef' as storage class VarDecl.");
+  VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec);
+  if (SCSpec == DeclSpec::SCS_mutable) {
     // mutable can only appear on non-static class members, so it's always
     // an error here
     Diag(D.getIdentifierLoc(), diag::err_mutable_nonmember);
     D.setInvalidType();
     SC = VarDecl::None;
-    break;
   }
+  SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
+  VarDecl::StorageClass SCAsWritten
+    = StorageClassSpecToVarDeclStorageClass(SCSpec);
 
   IdentifierInfo *II = Name.getAsIdentifierInfo();
   if (!II) {
@@ -2423,8 +2455,8 @@
     }
   }
 
-  NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
-                          II, R, TInfo, SC);
+  VarDecl *NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
+                                   II, R, TInfo, SC, SCAsWritten);
 
   if (D.isInvalidType())
     NewVD->setInvalidDecl();
@@ -2802,6 +2834,10 @@
   bool isVirtual = D.getDeclSpec().isVirtualSpecified();
   bool isExplicit = D.getDeclSpec().isExplicitSpecified();
 
+  DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
+  FunctionDecl::StorageClass SCAsWritten
+    = StorageClassSpecToFunctionDeclStorageClass(SCSpec);
+
   // Check that the return type is not an abstract class type.
   // For record types, this is done by the AbstractClassUsageDiagnoser once
   // the class has been completely parsed.
@@ -2862,7 +2898,7 @@
       // Create a FunctionDecl to satisfy the function definition parsing
       // code path.
       NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(),
-                                   Name, R, TInfo, SC, isInline,
+                                   Name, R, TInfo, SC, SCAsWritten, isInline,
                                    /*hasPrototype=*/true);
       D.setInvalidType();
     }
@@ -2911,7 +2947,7 @@
     // This is a C++ method declaration.
     NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
                                   D.getIdentifierLoc(), Name, R, TInfo,
-                                  isStatic, isInline);
+                                  isStatic, SCAsWritten, isInline);
 
     isVirtualOkay = !isStatic;
   } else {
@@ -2928,7 +2964,8 @@
 
     NewFD = FunctionDecl::Create(Context, DC,
                                  D.getIdentifierLoc(),
-                                 Name, R, TInfo, SC, isInline, HasPrototype);
+                                 Name, R, TInfo, SC, SCAsWritten, isInline,
+                                 HasPrototype);
   }
 
   if (D.isInvalidType())
@@ -3128,6 +3165,7 @@
       ParmVarDecl *Param = ParmVarDecl::Create(Context, NewFD,
                                                SourceLocation(), 0,
                                                *AI, /*TInfo=*/0,
+                                               VarDecl::None,
                                                VarDecl::None, 0);
       Param->setImplicit();
       Params.push_back(Param);
@@ -4088,8 +4126,10 @@
 
   // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
   VarDecl::StorageClass StorageClass = VarDecl::None;
+  VarDecl::StorageClass StorageClassAsWritten = VarDecl::None;
   if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
     StorageClass = VarDecl::Register;
+    StorageClassAsWritten = VarDecl::Register;
   } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
     Diag(DS.getStorageClassSpecLoc(),
          diag::err_invalid_storage_class_in_func_decl);
@@ -4147,7 +4187,8 @@
   // looking like class members in C++.
   ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(),
                                     TInfo, parmDeclType, II, 
-                                    D.getIdentifierLoc(), StorageClass);
+                                    D.getIdentifierLoc(),
+                                    StorageClass, StorageClassAsWritten);
 
   if (D.isInvalidType())
     New->setInvalidDecl();  
@@ -4176,10 +4217,12 @@
                                   TypeSourceInfo *TSInfo, QualType T,
                                   IdentifierInfo *Name,
                                   SourceLocation NameLoc,
-                                  VarDecl::StorageClass StorageClass) {
+                                  VarDecl::StorageClass StorageClass,
+                                  VarDecl::StorageClass StorageClassAsWritten) {
   ParmVarDecl *New = ParmVarDecl::Create(Context, DC, NameLoc, Name,
                                          adjustParameterType(T), TSInfo, 
-                                         StorageClass, 0);
+                                         StorageClass, StorageClassAsWritten,
+                                         0);
 
   // Parameters can not be abstract class types.
   // For record types, this is done by the AbstractClassUsageDiagnoser once
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 6a1451a..1c07d9b 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -1978,7 +1978,8 @@
     NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
                            VD->getLocation(), II,
                            VD->getType(), VD->getTypeSourceInfo(),
-                           VD->getStorageClass());
+                           VD->getStorageClass(),
+                           VD->getStorageClassAsWritten());
     if (VD->getQualifier()) {
       VarDecl *NewVD = cast<VarDecl>(NewD);
       NewVD->setQualifierInfo(VD->getQualifier(), VD->getQualifierRange());
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index c6fd53c..c8a3a8a 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2385,6 +2385,7 @@
                                                  ClassDecl->getLocation(),
                                                  /*IdentifierInfo=*/0,
                                                  ArgType, /*TInfo=*/0,
+                                                 VarDecl::None,
                                                  VarDecl::None, 0);
     CopyConstructor->setParams(&FromParam, 1);
     if (S)
@@ -2464,7 +2465,9 @@
                                                     /*FIXME:*/false,
                                                     false, 0, 0,
                                                     FunctionType::ExtInfo()),
-                            /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
+                            /*TInfo=*/0, /*isStatic=*/false,
+                            /*StorageClassAsWritten=*/FunctionDecl::None,
+                            /*isInline=*/true);
     CopyAssignment->setAccess(AS_public);
     CopyAssignment->setImplicit();
     CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
@@ -2475,6 +2478,7 @@
                                                  ClassDecl->getLocation(),
                                                  /*IdentifierInfo=*/0,
                                                  ArgType, /*TInfo=*/0,
+                                                 VarDecl::None,
                                                  VarDecl::None, 0);
     CopyAssignment->setParams(&FromParam, 1);
 
@@ -4787,7 +4791,8 @@
     Invalid = true;
 
   VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc,
-                                    Name, ExDeclType, TInfo, VarDecl::None);
+                                    Name, ExDeclType, TInfo, VarDecl::None,
+                                    VarDecl::None);
 
   if (!Invalid) {
     if (const RecordType *RecordTy = ExDeclType->getAs<RecordType>()) {
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index cc1aab4..e1973fa 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -1565,7 +1565,7 @@
     ParmVarDecl* Param
       = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc,
                             ArgInfo[i].Name, ArgType, DI,
-                            VarDecl::None, 0);
+                            VarDecl::None, VarDecl::None, 0);
 
     if (ArgType->isObjCInterfaceType()) {
       Diag(ArgInfo[i].NameLoc,
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index aa9efed..9440772 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1208,7 +1208,8 @@
                                             FunctionType::ExtInfo());
   FunctionDecl *Alloc =
     FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
-                         FnType, /*TInfo=*/0, FunctionDecl::None, false, true);
+                         FnType, /*TInfo=*/0, FunctionDecl::None,
+                         FunctionDecl::None, false, true);
   Alloc->setImplicit();
   
   if (AddMallocAttr)
@@ -1216,6 +1217,7 @@
   
   ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
                                            0, Argument, /*TInfo=*/0,
+                                           VarDecl::None,
                                            VarDecl::None, 0);
   Alloc->setParams(&Param, 1);
 
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index c73d815..d47d6c2 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -953,6 +953,7 @@
                                                   property->getType(),
                                                   /*TInfo=*/0,
                                                   VarDecl::None,
+                                                  VarDecl::None,
                                                   0);
       SetterMethod->setMethodParams(Context, &Argument, 1, 1);
       CD->addDecl(SetterMethod);
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index a2bd37c..e35d988 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -991,7 +991,8 @@
                                         NewDI, NewDI->getType(),
                                         OldParm->getIdentifier(),
                                         OldParm->getLocation(),
-                                        OldParm->getStorageClass());
+                                        OldParm->getStorageClass(),
+                                        OldParm->getStorageClassAsWritten());
   if (!NewParm)
     return 0;
                                                 
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 18b6829..10fe176 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -322,7 +322,8 @@
   VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner,
                                  D->getLocation(), D->getIdentifier(),
                                  DI->getType(), DI,
-                                 D->getStorageClass());
+                                 D->getStorageClass(),
+                                 D->getStorageClassAsWritten());
   Var->setThreadSpecified(D->isThreadSpecified());
   Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
   Var->setDeclaredInCondition(D->isDeclaredInCondition());
@@ -991,7 +992,7 @@
   FunctionDecl *Function =
       FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
                            D->getDeclName(), T, TInfo,
-                           D->getStorageClass(),
+                           D->getStorageClass(), D->getStorageClassAsWritten(),
                            D->isInlineSpecified(), D->hasWrittenPrototype());
 
   if (Qualifier)
@@ -1210,14 +1211,16 @@
                                         Constructor->getLocation(),
                                         Name, T, TInfo,
                                         Constructor->isExplicit(),
-                                        Constructor->isInlineSpecified(), false);
+                                        Constructor->isInlineSpecified(),
+                                        false);
   } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
     QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
     Name = SemaRef.Context.DeclarationNames.getCXXDestructorName(
                                    SemaRef.Context.getCanonicalType(ClassTy));
     Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
                                        Destructor->getLocation(), Name,
-                                       T, Destructor->isInlineSpecified(), false);
+                                       T, Destructor->isInlineSpecified(),
+                                       false);
   } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
     CanQualType ConvTy
       = SemaRef.Context.getCanonicalType(
@@ -1232,7 +1235,9 @@
   } else {
     Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
                                    D->getDeclName(), T, TInfo,
-                                   D->isStatic(), D->isInlineSpecified());
+                                   D->isStatic(),
+                                   D->getStorageClassAsWritten(),
+                                   D->isInlineSpecified());
   }
 
   if (Qualifier)
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index f9ffd3f..e2fdf66 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -2630,6 +2630,7 @@
                                NewDI->getType(),
                                NewDI,
                                OldParm->getStorageClass(),
+                               OldParm->getStorageClassAsWritten(),
                                /* DefArg */ NULL);
 }