Anastasia created this revision.
Anastasia added reviewers: rjmccall, ebevhan.

Here is my attempt to generalize the earlier work on method overloading with 
address spaces https://reviews.llvm.org/D55850 to work in C++ mode (not just 
OpenCL!).

This implementation doesn't apply yet to templated addr spaces because I would 
need to perform modifications on the extended function info. Also a couple of 
smaller corner cases are not handled. However, if the general direction is 
right, the rest can be build on top of this patch.


https://reviews.llvm.org/D57464

Files:
  lib/Parse/ParseDeclCXX.cpp
  lib/Sema/SemaType.cpp
  test/SemaCXX/address-space-method-overloading.cpp

Index: test/SemaCXX/address-space-method-overloading.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/address-space-method-overloading.cpp
@@ -0,0 +1,29 @@
+//RUN: %clang_cc1 %s -pedantic -verify
+
+struct TestAS1 {
+  int i;
+};
+
+struct TestAS2 {
+  char c;
+};
+
+struct C {
+TestAS1 bar() __attribute__((address_space(1))); // expected-note{{candidate function not viable: address space mismatch in 'this' argument ('__attribute__((address_space(3))) C'), parameter type must be '__attribute__((address_space(1))) C'}} expected-note{{candidate function}}
+TestAS2 bar() __attribute__((address_space(2))); // expected-note{{candidate function not viable: address space mismatch in 'this' argument ('__attribute__((address_space(3))) C'), parameter type must be '__attribute__((address_space(2))) C'}} expected-note{{candidate function}}
+void multiple_as() __attribute__((address_space(1))) __attribute__((address_space(2))); //expected-error{{multiple address spaces specified for type}} 
+// FIXME: Parser gets confused here.
+//auto bar() __attribute__((address_space(4))) -> decltype(this);
+};
+
+__attribute__((address_space(1))) C inas1;
+__attribute__((address_space(3))) C inas3;
+__attribute__((address_space(4))) C inas4;
+
+void foo() {
+   C noas;
+   TestAS1 ret = inas1.bar();
+   inas3.bar(); // expected-error{{no matching member function for call to 'bar'}}
+   //inas4.bar();
+   noas.bar(); // expected-error{{call to member function 'bar' is ambiguous}}
+}
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -3939,6 +3939,9 @@
   return false;
 }
 
+static bool ProcessAddressSpaceAttribute(Sema &S, const ParsedAttr &Attr,
+                                         LangAS &ASIdx, Expr *&ASArgExpr);
+
 static TypeSourceInfo *
 GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
                                QualType T, TypeSourceInfo *ReturnTypeInfo);
@@ -4857,25 +4860,46 @@
                  state.getDeclarator().getContext() ==
                      DeclaratorContext::MemberContext;
         };
-
-        if (state.getSema().getLangOpts().OpenCLCPlusPlus && IsClassMember()) {
-          LangAS ASIdx = LangAS::Default;
+        if (IsClassMember()) {
+          auto CheckAS =
+              state.getSema().getLangOpts().OpenCLCPlusPlus
+                  ? std::function<LangAS(ParsedAttr & attr)>{[&](ParsedAttr
+                                                                     &attr) {
+                      return attr.asOpenCLLangAS();
+                    }}
+                  : std::function<LangAS(ParsedAttr & attr)>{
+                        [&](ParsedAttr &attr) {
+                          LangAS AS = LangAS::Default;
+                          if (attr.getKind() == ParsedAttr::AT_AddressSpace) {
+                            Expr *ASArgExpr = nullptr;
+                            ProcessAddressSpaceAttribute(S, attr, AS,
+                                                         ASArgExpr);
+                            // FIXME: We should extend logic to cover this case
+                            // or at least give an error?
+                            if (ASArgExpr->isValueDependent())
+                              ;
+                          }
+                          return AS;
+                        }};
+          LangAS AS = LangAS::Default;
           // Take address space attr if any and mark as invalid to avoid adding
           // them later while creating QualType.
           if (FTI.MethodQualifiers)
             for (ParsedAttr &attr : FTI.MethodQualifiers->getAttributes()) {
-              LangAS ASIdxNew = attr.asOpenCLLangAS();
-              if (DiagnoseMultipleAddrSpaceAttributes(S, ASIdx, ASIdxNew,
+              LangAS ASNew = CheckAS(attr);
+              if (DiagnoseMultipleAddrSpaceAttributes(S, AS, ASNew,
                                                       attr.getLoc()))
                 D.setInvalidType(true);
               else
-                ASIdx = ASIdxNew;
+                AS = ASNew;
             }
-          // If a class member function's address space is not set, set it to
-          // __generic.
-          LangAS AS =
-              (ASIdx == LangAS::Default ? LangAS::opencl_generic : ASIdx);
-          EPI.TypeQuals.addAddressSpace(AS);
+          // For OpenCL if a class member function's address space is not set,
+          // set it to __generic.
+          if (state.getSema().getLangOpts().OpenCLCPlusPlus &&
+              AS == LangAS::Default)
+            AS = LangAS::opencl_generic;
+          if (AS != LangAS::Default)
+            EPI.TypeQuals.addAddressSpace(AS);
         }
         T = Context.getFunctionType(T, ParamTys, EPI);
       }
@@ -5836,6 +5860,43 @@
   return true;
 }
 
+/// Process the address space and diagnose any issues. On success its numerical
+/// value and argument expression will be filled in. Returns value indicating
+/// whether any diagnostic occurred.
+static bool ProcessAddressSpaceAttribute(Sema &S, const ParsedAttr &Attr,
+                                         LangAS &ASIdx, Expr *&ASArgExpr) {
+  // Check the attribute arguments.
+  if (Attr.getNumArgs() != 1) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+        << Attr << 1;
+    Attr.setInvalid();
+    return false;
+  }
+
+  if (Attr.isArgIdent(0)) {
+    // Special case where the argument is a template id.
+    CXXScopeSpec SS;
+    SourceLocation TemplateKWLoc;
+    UnqualifiedId id;
+    id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc());
+
+    ExprResult AddrSpace = S.ActOnIdExpression(S.getCurScope(), SS,
+                                               TemplateKWLoc, id, false, false);
+    if (AddrSpace.isInvalid())
+      return false;
+
+    ASArgExpr = static_cast<Expr *>(AddrSpace.get());
+  } else {
+    ASArgExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
+  }
+
+  if (!BuildAddressSpaceIndex(S, ASIdx, ASArgExpr, Attr.getLoc())) {
+    Attr.setInvalid();
+    return false;
+  }
+  return true;
+}
+
 /// BuildAddressSpaceAttr - Builds a DependentAddressSpaceType if an expression
 /// is uninstantiated. If instantiated it will apply the appropriate address
 /// space to the type. This function allows dependent template variables to be
@@ -5887,9 +5948,8 @@
     return;
   }
 
-  LangAS ASIdx;
+  LangAS ASIdx = LangAS::Default;
   if (Attr.getKind() == ParsedAttr::AT_AddressSpace) {
-
     // Check the attribute arguments.
     if (Attr.getNumArgs() != 1) {
       S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Attr
@@ -5897,30 +5957,9 @@
       Attr.setInvalid();
       return;
     }
-
-    Expr *ASArgExpr;
-    if (Attr.isArgIdent(0)) {
-      // Special case where the argument is a template id.
-      CXXScopeSpec SS;
-      SourceLocation TemplateKWLoc;
-      UnqualifiedId id;
-      id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc());
-
-      ExprResult AddrSpace = S.ActOnIdExpression(
-          S.getCurScope(), SS, TemplateKWLoc, id, false, false);
-      if (AddrSpace.isInvalid())
-        return;
-
-      ASArgExpr = static_cast<Expr *>(AddrSpace.get());
-    } else {
-      ASArgExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
-    }
-
-    LangAS ASIdx;
-    if (!BuildAddressSpaceIndex(S, ASIdx, ASArgExpr, Attr.getLoc())) {
-      Attr.setInvalid();
+    Expr *ASArgExpr = nullptr;
+    if (!ProcessAddressSpaceAttribute(S, Attr, ASIdx, ASArgExpr))
       return;
-    }
 
     ASTContext &Ctx = S.Context;
     auto *ASAttr = ::new (Ctx) AddressSpaceAttr(
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -2298,6 +2298,19 @@
 
   // If attributes exist after the declarator, but before an '{', parse them.
   MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
+  if (DeclaratorInfo.isFunctionDeclarator()) {
+    auto &Function = DeclaratorInfo.getFunctionTypeInfo();
+    auto &MQ = Function.getOrCreateMethodQualifiers();
+    for (auto &attr : DeclaratorInfo.getAttributes()) {
+      if (attr.getKind() == ParsedAttr::AT_AddressSpace) {
+        auto AU = attr.getArg(0);
+        MQ.getAttributes().addNew(attr.getName(), attr.getRange(),
+                                  attr.getScopeName(), attr.getScopeLoc(), &AU,
+                                  attr.getNumArgs(), ParsedAttr::AS_GNU);
+        attr.setInvalid();
+      }
+    }
+  }
 
   // For compatibility with code written to older Clang, also accept a
   // virt-specifier *after* the GNU attributes.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to