Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -683,6 +683,8 @@ ExprRep = Rep; } + bool SetTypeQual(TQ T, SourceLocation Loc); + bool SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, const LangOptions &Lang); @@ -1250,10 +1252,6 @@ /// Otherwise, it's an rvalue reference. unsigned RefQualifierIsLValueRef : 1; - /// The type qualifiers: const/volatile/restrict/__unaligned - /// The qualifier bitmask values are the same as in QualType. - unsigned TypeQuals : 4; - /// ExceptionSpecType - An ExceptionSpecificationType value. unsigned ExceptionSpecType : 4; @@ -1287,21 +1285,6 @@ /// If this is an invalid location, there is no ref-qualifier. unsigned RefQualifierLoc; - /// The location of the const-qualifier, if any. - /// - /// If this is an invalid location, there is no const-qualifier. - unsigned ConstQualifierLoc; - - /// The location of the volatile-qualifier, if any. - /// - /// If this is an invalid location, there is no volatile-qualifier. - unsigned VolatileQualifierLoc; - - /// The location of the restrict-qualifier, if any. - /// - /// If this is an invalid location, there is no restrict-qualifier. - unsigned RestrictQualifierLoc; - /// The location of the 'mutable' qualifer in a lambda-declarator, if /// any. unsigned MutableLoc; @@ -1317,6 +1300,9 @@ /// there are no parameters specified. ParamInfo *Params; + /// DeclSpec for the function with the qualifier related info. + DeclSpec *TypeDeclSpec; + union { /// Pointer to a new[]'d array of TypeAndRange objects that /// contain the types in the function's dynamic exception specification @@ -1356,6 +1342,7 @@ void destroy() { freeParams(); + delete TypeDeclSpec; switch (getExceptionSpecType()) { default: break; @@ -1408,17 +1395,17 @@ /// Retrieve the location of the 'const' qualifier, if any. SourceLocation getConstQualifierLoc() const { - return SourceLocation::getFromRawEncoding(ConstQualifierLoc); + return TypeDeclSpec->getConstSpecLoc(); } /// Retrieve the location of the 'volatile' qualifier, if any. SourceLocation getVolatileQualifierLoc() const { - return SourceLocation::getFromRawEncoding(VolatileQualifierLoc); + return TypeDeclSpec->getVolatileSpecLoc(); } /// Retrieve the location of the 'restrict' qualifier, if any. SourceLocation getRestrictQualifierLoc() const { - return SourceLocation::getFromRawEncoding(RestrictQualifierLoc); + return TypeDeclSpec->getRestrictSpecLoc(); } /// Retrieve the location of the 'mutable' qualifier, if any. @@ -1574,12 +1561,8 @@ ParamInfo *Params, unsigned NumParams, SourceLocation EllipsisLoc, SourceLocation RParenLoc, - unsigned TypeQuals, bool RefQualifierIsLvalueRef, SourceLocation RefQualifierLoc, - SourceLocation ConstQualifierLoc, - SourceLocation VolatileQualifierLoc, - SourceLocation RestrictQualifierLoc, SourceLocation MutableLoc, ExceptionSpecificationType ESpecType, SourceRange ESpecRange, @@ -1593,7 +1576,8 @@ SourceLocation LocalRangeEnd, Declarator &TheDeclarator, TypeResult TrailingReturnType = - TypeResult()); + TypeResult(), + DeclSpec *TypeDeclSpec = nullptr); /// Return a DeclaratorChunk for a block. static DeclaratorChunk getBlockPointer(unsigned TypeQuals, Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -6069,7 +6069,7 @@ // Remember where we see an ellipsis, if any. SourceLocation EllipsisLoc; - DeclSpec DS(AttrFactory); + DeclSpec *DS = nullptr; bool RefQualifierIsLValueRef = true; SourceLocation RefQualifierLoc; SourceLocation ConstQualifierLoc; @@ -6124,22 +6124,23 @@ EndLoc = RParenLoc; if (getLangOpts().CPlusPlus) { + // In C++ we always query qualifiers or add them implicitly, therefore + // create DeclSpec here to be populated later. + DS = new DeclSpec(AttrFactory); + // FIXME: Accept these components in any order, and produce fixits to // correct the order if the user gets it wrong. Ideally we should deal // with the pure-specifier in the same way. // Parse cv-qualifier-seq[opt]. - ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, - /*AtomicAllowed*/ false, - /*IdentifierRequired=*/false, - llvm::function_ref([&]() { - Actions.CodeCompleteFunctionQualifiers(DS, D); - })); - if (!DS.getSourceRange().getEnd().isInvalid()) { - EndLoc = DS.getSourceRange().getEnd(); - ConstQualifierLoc = DS.getConstSpecLoc(); - VolatileQualifierLoc = DS.getVolatileSpecLoc(); - RestrictQualifierLoc = DS.getRestrictSpecLoc(); + ParseTypeQualifierListOpt( + *DS, AR_NoAttributesParsed, + /*AtomicAllowed*/ false, + /*IdentifierRequired=*/false, llvm::function_ref([&]() { + Actions.CodeCompleteFunctionQualifiers(*DS, D); + })); + if (!DS->getSourceRange().getEnd().isInvalid()) { + EndLoc = DS->getSourceRange().getEnd(); } // Parse ref-qualifier[opt]. @@ -6154,15 +6155,15 @@ // declarator. // FIXME: currently, "static" case isn't handled correctly. bool IsCXX11MemberFunction = - getLangOpts().CPlusPlus11 && - D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && - (D.getContext() == DeclaratorContext::MemberContext - ? !D.getDeclSpec().isFriendSpecified() - : D.getContext() == DeclaratorContext::FileContext && - D.getCXXScopeSpec().isValid() && - Actions.CurContext->isRecord()); - - Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers()); + getLangOpts().CPlusPlus11 && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && + (D.getContext() == DeclaratorContext::MemberContext + ? !D.getDeclSpec().isFriendSpecified() + : D.getContext() == DeclaratorContext::FileContext && + D.getCXXScopeSpec().isValid() && + Actions.CurContext->isRecord()); + + Qualifiers Q = Qualifiers::fromCVRUMask(DS->getTypeQualifiers()); if (D.getDeclSpec().isConstexprSpecified() && !getLangOpts().CPlusPlus14) Q.addConst(); @@ -6239,15 +6240,13 @@ D.AddTypeInfo(DeclaratorChunk::getFunction( HasProto, IsAmbiguous, LParenLoc, ParamInfo.data(), ParamInfo.size(), EllipsisLoc, RParenLoc, - DS.getTypeQualifiers(), RefQualifierIsLValueRef, - RefQualifierLoc, ConstQualifierLoc, VolatileQualifierLoc, - RestrictQualifierLoc, - /*MutableLoc=*/SourceLocation(), ESpecType, ESpecRange, - DynamicExceptions.data(), DynamicExceptionRanges.data(), - DynamicExceptions.size(), + RefQualifierIsLValueRef, RefQualifierLoc, + /*MutableLoc=*/SourceLocation(), + ESpecType, ESpecRange, DynamicExceptions.data(), + DynamicExceptionRanges.data(), DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, ExceptionSpecTokens, DeclsInPrototype, StartLoc, - LocalEndLoc, D, TrailingReturnType), + LocalEndLoc, D, TrailingReturnType, DS), std::move(FnAttrs), EndLoc); } Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -2346,32 +2346,25 @@ if (D.isFunctionDeclarator()) { auto &Function = D.getFunctionTypeInfo(); if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) { - auto DeclSpecCheck = [&] (DeclSpec::TQ TypeQual, - const char *FixItName, - SourceLocation SpecLoc, - unsigned* QualifierLoc) { + auto DeclSpecCheck = [&](DeclSpec::TQ TypeQual, const char *FixItName, + SourceLocation SpecLoc) { FixItHint Insertion; if (DS.getTypeQualifiers() & TypeQual) { - if (!(Function.TypeQuals & TypeQual)) { + if (!(Function.TypeDeclSpec->getTypeQualifiers() & TypeQual)) { std::string Name(FixItName); Name += " "; Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name); - Function.TypeQuals |= TypeQual; - *QualifierLoc = SpecLoc.getRawEncoding(); + Function.TypeDeclSpec->SetTypeQual(TypeQual, SpecLoc); } Diag(SpecLoc, diag::err_declspec_after_virtspec) - << FixItName - << VirtSpecifiers::getSpecifierName(VS.getLastSpecifier()) - << FixItHint::CreateRemoval(SpecLoc) - << Insertion; + << FixItName + << VirtSpecifiers::getSpecifierName(VS.getLastSpecifier()) + << FixItHint::CreateRemoval(SpecLoc) << Insertion; } }; - DeclSpecCheck(DeclSpec::TQ_const, "const", DS.getConstSpecLoc(), - &Function.ConstQualifierLoc); - DeclSpecCheck(DeclSpec::TQ_volatile, "volatile", DS.getVolatileSpecLoc(), - &Function.VolatileQualifierLoc); - DeclSpecCheck(DeclSpec::TQ_restrict, "restrict", DS.getRestrictSpecLoc(), - &Function.RestrictQualifierLoc); + DeclSpecCheck(DeclSpec::TQ_const, "const", DS.getConstSpecLoc()); + DeclSpecCheck(DeclSpec::TQ_volatile, "volatile", DS.getVolatileSpecLoc()); + DeclSpecCheck(DeclSpec::TQ_restrict, "restrict", DS.getRestrictSpecLoc()); } // Parse ref-qualifiers. Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -3012,12 +3012,8 @@ /*NumArgs=*/0, /*EllipsisLoc=*/NoLoc, /*RParenLoc=*/NoLoc, - /*TypeQuals=*/0, /*RefQualifierIsLvalueRef=*/true, /*RefQualifierLoc=*/NoLoc, - /*ConstQualifierLoc=*/NoLoc, - /*VolatileQualifierLoc=*/NoLoc, - /*RestrictQualifierLoc=*/NoLoc, /*MutableLoc=*/NoLoc, EST_None, /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, Index: lib/Parse/ParseExprCXX.cpp =================================================================== --- lib/Parse/ParseExprCXX.cpp +++ lib/Parse/ParseExprCXX.cpp @@ -1206,18 +1206,14 @@ /*hasProto=*/true, /*isAmbiguous=*/false, LParenLoc, ParamInfo.data(), ParamInfo.size(), EllipsisLoc, RParenLoc, - DS.getTypeQualifiers(), /*RefQualifierIsLValueRef=*/true, - /*RefQualifierLoc=*/NoLoc, - /*ConstQualifierLoc=*/NoLoc, - /*VolatileQualifierLoc=*/NoLoc, - /*RestrictQualifierLoc=*/NoLoc, MutableLoc, ESpecType, + /*RefQualifierLoc=*/NoLoc, MutableLoc, ESpecType, ESpecRange, DynamicExceptions.data(), DynamicExceptionRanges.data(), DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, /*ExceptionSpecTokens*/ nullptr, /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D, - TrailingReturnType), + TrailingReturnType, new DeclSpec(AttrFactory)), std::move(Attr), DeclEndLoc); } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute, tok::kw_constexpr) || @@ -1273,12 +1269,8 @@ /*NumParams=*/0, /*EllipsisLoc=*/NoLoc, /*RParenLoc=*/NoLoc, - /*TypeQuals=*/0, /*RefQualifierIsLValueRef=*/true, - /*RefQualifierLoc=*/NoLoc, - /*ConstQualifierLoc=*/NoLoc, - /*VolatileQualifierLoc=*/NoLoc, - /*RestrictQualifierLoc=*/NoLoc, MutableLoc, EST_None, + /*RefQualifierLoc=*/NoLoc, MutableLoc, EST_None, /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, @@ -1286,7 +1278,7 @@ /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, /*DeclsInPrototype=*/None, DeclLoc, DeclEndLoc, D, - TrailingReturnType), + TrailingReturnType, new DeclSpec(AttrFactory)), std::move(Attr), DeclEndLoc); } Index: lib/Sema/DeclSpec.cpp =================================================================== --- lib/Sema/DeclSpec.cpp +++ lib/Sema/DeclSpec.cpp @@ -156,14 +156,8 @@ unsigned NumParams, SourceLocation EllipsisLoc, SourceLocation RParenLoc, - unsigned TypeQuals, bool RefQualifierIsLvalueRef, SourceLocation RefQualifierLoc, - SourceLocation ConstQualifierLoc, - SourceLocation - VolatileQualifierLoc, - SourceLocation - RestrictQualifierLoc, SourceLocation MutableLoc, ExceptionSpecificationType ESpecType, @@ -178,8 +172,9 @@ SourceLocation LocalRangeBegin, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, - TypeResult TrailingReturnType) { - assert(!(TypeQuals & DeclSpec::TQ_atomic) && + TypeResult TrailingReturnType, + DeclSpec* TypeDeclSpec) { + assert(!(TypeDeclSpec && (TypeDeclSpec->getTypeQualifiers() & DeclSpec::TQ_atomic)) && "function cannot have _Atomic qualifier"); DeclaratorChunk I; @@ -193,14 +188,10 @@ I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding(); I.Fun.RParenLoc = RParenLoc.getRawEncoding(); I.Fun.DeleteParams = false; - I.Fun.TypeQuals = TypeQuals; I.Fun.NumParams = NumParams; I.Fun.Params = nullptr; I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef; I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding(); - I.Fun.ConstQualifierLoc = ConstQualifierLoc.getRawEncoding(); - I.Fun.VolatileQualifierLoc = VolatileQualifierLoc.getRawEncoding(); - I.Fun.RestrictQualifierLoc = RestrictQualifierLoc.getRawEncoding(); I.Fun.MutableLoc = MutableLoc.getRawEncoding(); I.Fun.ExceptionSpecType = ESpecType; I.Fun.ExceptionSpecLocBeg = ESpecRange.getBegin().getRawEncoding(); @@ -211,8 +202,8 @@ I.Fun.HasTrailingReturnType = TrailingReturnType.isUsable() || TrailingReturnType.isInvalid(); I.Fun.TrailingReturnType = TrailingReturnType.get(); + I.Fun.TypeDeclSpec = TypeDeclSpec; - assert(I.Fun.TypeQuals == TypeQuals && "bitfield overflow"); assert(I.Fun.ExceptionSpecType == ESpecType && "bitfield overflow"); // new[] a parameter array if needed. @@ -862,6 +853,11 @@ IsExtension = false; return BadSpecifier(T, T, PrevSpec, DiagID, IsExtension); } + + return SetTypeQual(T, Loc); +} + +bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc) { TypeQualifiers |= T; switch (T) { Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -13513,12 +13513,8 @@ /*NumParams=*/0, /*EllipsisLoc=*/NoLoc, /*RParenLoc=*/NoLoc, - /*TypeQuals=*/0, /*RefQualifierIsLvalueRef=*/true, /*RefQualifierLoc=*/NoLoc, - /*ConstQualifierLoc=*/NoLoc, - /*VolatileQualifierLoc=*/NoLoc, - /*RestrictQualifierLoc=*/NoLoc, /*MutableLoc=*/NoLoc, EST_None, /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -8172,16 +8172,16 @@ } DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); - if (FTI.TypeQuals != 0) { - if (FTI.TypeQuals & Qualifiers::Const) + if (FTI.TypeDeclSpec->getTypeQualifiers() != 0) { + if (FTI.TypeDeclSpec->getTypeQualifiers() & Qualifiers::Const) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) - << "const" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & Qualifiers::Volatile) + << "const" << SourceRange(D.getIdentifierLoc()); + if (FTI.TypeDeclSpec->getTypeQualifiers() & Qualifiers::Volatile) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) - << "volatile" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & Qualifiers::Restrict) + << "volatile" << SourceRange(D.getIdentifierLoc()); + if (FTI.TypeDeclSpec->getTypeQualifiers() & Qualifiers::Restrict) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) - << "restrict" << SourceRange(D.getIdentifierLoc()); + << "restrict" << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); } @@ -8361,16 +8361,16 @@ } DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); - if (FTI.TypeQuals != 0 && !D.isInvalidType()) { - if (FTI.TypeQuals & Qualifiers::Const) + if (FTI.TypeDeclSpec->getTypeQualifiers() != 0 && !D.isInvalidType()) { + if (FTI.TypeDeclSpec->getTypeQualifiers() & Qualifiers::Const) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) - << "const" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & Qualifiers::Volatile) + << "const" << SourceRange(D.getIdentifierLoc()); + if (FTI.TypeDeclSpec->getTypeQualifiers() & Qualifiers::Volatile) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) - << "volatile" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & Qualifiers::Restrict) + << "volatile" << SourceRange(D.getIdentifierLoc()); + if (FTI.TypeDeclSpec->getTypeQualifiers() & Qualifiers::Restrict) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) - << "restrict" << SourceRange(D.getIdentifierLoc()); + << "restrict" << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); } Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -884,8 +884,9 @@ // This function call operator is declared const (9.3.1) if and only if // the lambda-expression's parameter-declaration-clause is not followed // by mutable. It is neither virtual nor declared volatile. [...] - if (!FTI.hasMutableQualifier()) - FTI.TypeQuals |= DeclSpec::TQ_const; + if (!FTI.hasMutableQualifier()) { + FTI.TypeDeclSpec->SetTypeQual(DeclSpec::TQ_const, SourceLocation()); + } MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope); assert(MethodTyInfo && "no type from lambda-declarator"); Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -724,12 +724,8 @@ /*NumArgs=*/0, /*EllipsisLoc=*/NoLoc, /*RParenLoc=*/NoLoc, - /*TypeQuals=*/0, /*RefQualifierIsLvalueRef=*/true, /*RefQualifierLoc=*/NoLoc, - /*ConstQualifierLoc=*/NoLoc, - /*VolatileQualifierLoc=*/NoLoc, - /*RestrictQualifierLoc=*/NoLoc, /*MutableLoc=*/NoLoc, EST_None, /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, @@ -4460,7 +4456,7 @@ // does not have a K&R-style identifier list), then the arguments are part // of the type, otherwise the argument list is (). const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; - IsQualifiedFunction = FTI.TypeQuals || FTI.hasRefQualifier(); + IsQualifiedFunction = (FTI.TypeDeclSpec && FTI.TypeDeclSpec->getTypeQualifiers()) || FTI.hasRefQualifier(); // Check for auto functions and trailing return type and adjust the // return type accordingly. @@ -4698,7 +4694,7 @@ EPI.ExtInfo = EI; EPI.Variadic = FTI.isVariadic; EPI.HasTrailingReturn = FTI.hasTrailingReturnType(); - EPI.TypeQuals.addCVRUQualifiers(FTI.TypeQuals); + EPI.TypeQuals.addCVRUQualifiers(FTI.TypeDeclSpec ? FTI.TypeDeclSpec->getTypeQualifiers() : 0); EPI.RefQualifier = !FTI.hasRefQualifier()? RQ_None : FTI.RefQualifierIsLValueRef? RQ_LValue : RQ_RValue; @@ -5026,11 +5022,11 @@ assert(Chunk.Kind == DeclaratorChunk::Function); if (Chunk.Fun.hasRefQualifier()) RemovalLocs.push_back(Chunk.Fun.getRefQualifierLoc()); - if (Chunk.Fun.TypeQuals & Qualifiers::Const) + if (Chunk.Fun.TypeDeclSpec->getTypeQualifiers() & Qualifiers::Const) RemovalLocs.push_back(Chunk.Fun.getConstQualifierLoc()); - if (Chunk.Fun.TypeQuals & Qualifiers::Volatile) + if (Chunk.Fun.TypeDeclSpec->getTypeQualifiers() & Qualifiers::Volatile) RemovalLocs.push_back(Chunk.Fun.getVolatileQualifierLoc()); - if (Chunk.Fun.TypeQuals & Qualifiers::Restrict) + if (Chunk.Fun.TypeDeclSpec->getTypeQualifiers() & Qualifiers::Restrict) RemovalLocs.push_back(Chunk.Fun.getRestrictQualifierLoc()); if (!RemovalLocs.empty()) { llvm::sort(RemovalLocs,