Reject template-ids containing literal-operator-ids that have a dependent
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. llvm-svn: 196443
This commit is contained in:
parent
b9a69f6129
commit
d091dc179d
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue