]> granicus.if.org Git - clang/commitdiff
Reject template-ids containing literal-operator-ids that have a dependent
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 5 Dec 2013 00:58:33 +0000 (00:58 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 5 Dec 2013 00:58:33 +0000 (00:58 +0000)
nested-name-specifier, rather than crashing. (In fact, reject all
literal-operator-ids that have a non-namespace nested-name-specifier). The
grammar doesn't allow these in some cases, and in other cases does allow them
but instantiation will always fail.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196443 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Parse/ParseExprCXX.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaTemplate.cpp
test/SemaCXX/cxx11-user-defined-literals.cpp

index d80e4f28566e48efcc8cecbfb92cdcf7b6165d45..e1ca10fc83bcc2873281d9c8e6716069ad8849d2 100644 (file)
@@ -6009,6 +6009,8 @@ def err_operator_delete_param_type : Error<
 // C++ literal operators
 def err_literal_operator_outside_namespace : Error<
   "literal operator %0 must be in a namespace or global scope">;
+def err_literal_operator_id_outside_namespace : Error<
+  "non-namespace scope '%0' cannot have a literal operator member">;
 def err_literal_operator_default_argument : Error<
   "literal operator cannot have a default argument">;
 // FIXME: This diagnostic sucks
index 3fbe2b78270310c190a7a359abd17d66b4534eed..1ad3194a7955c7c8456be5bd79637d7b436bc189 100644 (file)
@@ -2478,6 +2478,7 @@ public:
                                         bool RValueThis, unsigned ThisQuals);
   CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class);
 
+  bool checkLiteralOperatorId(const CXXScopeSpec &SS, const UnqualifiedId &Id);
   LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R,
                                                     ArrayRef<QualType> ArgTys,
                                                     bool AllowRaw,
index f07428a0f3f41ab20b5b14ac2cd259116af6428a..9489b4787e25a4b7d345776a4910edbd0266e5d9 100644 (file)
@@ -287,19 +287,23 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
 
       TentativeParsingAction TPA(*this);
       SourceLocation TemplateKWLoc = ConsumeToken();
-      
+
       UnqualifiedId TemplateName;
       if (Tok.is(tok::identifier)) {
         // Consume the identifier.
         TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
         ConsumeToken();
       } else if (Tok.is(tok::kw_operator)) {
-        if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, 
+        // We don't need to actually parse the unqualified-id in this case,
+        // because a simple-template-id cannot start with 'operator', but
+        // go ahead and parse it anyway for consistency with the case where
+        // we already annotated the template-id.
+        if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType,
                                        TemplateName)) {
           TPA.Commit();
           break;
         }
-        
+
         if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId &&
             TemplateName.getKind() != UnqualifiedId::IK_LiteralOperatorId) {
           Diag(TemplateName.getSourceRange().getBegin(),
@@ -2131,9 +2135,10 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
     }
 
     Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc);
-    return false;
+
+    return Actions.checkLiteralOperatorId(SS, Result);
   }
-  
+
   // Parse a conversion-function-id.
   //
   //   conversion-function-id: [C++ 12.3.2]
index 6ad042991c2717ec7d207397082152bb076f9a4e..6273ce19f5e7987511c4ece99069d0922dec95f6 100644 (file)
@@ -333,6 +333,34 @@ ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) {
     return ParsedType();
 }
 
+bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS,
+                                  const UnqualifiedId &Name) {
+  assert(Name.getKind() == UnqualifiedId::IK_LiteralOperatorId);
+
+  if (!SS.isValid())
+    return false;
+
+  switch (SS.getScopeRep()->getKind()) {
+  case NestedNameSpecifier::Identifier:
+  case NestedNameSpecifier::TypeSpec:
+  case NestedNameSpecifier::TypeSpecWithTemplate:
+    // Per C++11 [over.literal]p2, literal operators can only be declared at
+    // namespace scope. Therefore, this unqualified-id cannot name anything.
+    // Reject it early, because we have no AST representation for this in the
+    // case where the scope is dependent.
+    Diag(Name.getLocStart(), diag::err_literal_operator_id_outside_namespace)
+      << SS.getScopeRep();
+    return true;
+
+  case NestedNameSpecifier::Global:
+  case NestedNameSpecifier::Namespace:
+  case NestedNameSpecifier::NamespaceAlias:
+    return false;
+  }
+
+  llvm_unreachable("unknown nested name specifier kind");
+}
+
 /// \brief Build a C++ typeid expression with a type operand.
 ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
                                 SourceLocation TypeidLoc,
index 3e55ec90ad063fd53f8068be4b81969445e1bb4d..b5b2f0dbedc7aa914b1b25fc244db61b37864236 100644 (file)
@@ -2914,8 +2914,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
     return TNK_Function_template;
 
   case UnqualifiedId::IK_LiteralOperatorId:
-    llvm_unreachable(
-            "We don't support these; Parse shouldn't have allowed propagation");
+    llvm_unreachable("literal operator id cannot have a dependent scope");
 
   default:
     break;
index f8bbcd960fd32ba4671b6a004fdf52b182192cd7..cb7796418ee31d4780ded646369ce754201576b3 100644 (file)
@@ -141,3 +141,27 @@ namespace PR14950 {
   int operator"" _b(); // expected-error {{no function template matches function template specialization}}
   int main() { return 0_b; } // expected-error {{no matching literal operator for call to 'operator "" _b'}}
 }
+
+namespace bad_names {
+  template<char...> int operator""_x();
+
+  template<typename T> void f() {
+    class T:: // expected-error {{anonymous class}} expected-warning {{does not declare anything}}
+        operator // expected-error {{expected identifier}}
+            ""_q<'a'>;
+
+    T::template operator""_q<'a'>(); // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}} expected-error +{{}}
+    T::template operator""_q<'a'>::X; // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}} expected-error +{{}}
+    T::operator""_q<'a'>(); // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}} expected-error +{{}}
+    typename T::template operator""_q<'a'> a; // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}} expected-error +{{}}
+    typename T::operator""_q(""); // expected-error +{{}} expected-note {{to match}}
+    T::operator""_q(""); // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}}
+
+    bad_names::operator""_x<'a', 'b', 'c'>();
+  };
+
+  struct S {};
+  void g() {
+    S::operator""_q(); // expected-error {{non-namespace scope 'S::' cannot have a literal operator member}}
+  }
+}