Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -593,6 +593,18 @@ FS_noreturnLoc = SourceLocation(); } + /// This method calls the passed in handler on each CVRU qual being + /// set. + /// Handle - a handler to be invoked. + void forEachCVRUQualifier( + llvm::function_ref Handle); + + /// This method calls the passed in handler on each qual being + /// set. + /// Handle - a handler to be invoked. + void forEachQualifier( + llvm::function_ref Handle); + /// Return true if any type-specifier has been found. bool hasTypeSpecifier() const { return getTypeSpecType() != DeclSpec::TST_unspecified || @@ -683,6 +695,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 +1264,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 +1297,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 +1312,12 @@ /// there are no parameters specified. ParamInfo *Params; + /// DeclSpec for the function with the qualifier related info. + DeclSpec *MethodQualifiers; + + /// AtttibuteFactory for the MethodQualifiers. + AttributeFactory *QualAttrFactory; + union { /// Pointer to a new[]'d array of TypeAndRange objects that /// contain the types in the function's dynamic exception specification @@ -1356,6 +1357,8 @@ void destroy() { freeParams(); + delete QualAttrFactory; + delete MethodQualifiers; switch (getExceptionSpecType()) { default: break; @@ -1372,6 +1375,14 @@ } } + DeclSpec &getOrCreateMethodQualifiers() { + if (!MethodQualifiers) { + QualAttrFactory = new AttributeFactory(); + MethodQualifiers = new DeclSpec(*QualAttrFactory); + } + return *MethodQualifiers; + } + /// isKNRPrototype - Return true if this is a K&R style identifier list, /// like "void foo(a,b,c)". In a function definition, this will be followed /// by the parameter type definitions. @@ -1406,19 +1417,22 @@ return SourceLocation::getFromRawEncoding(RefQualifierLoc); } - /// Retrieve the location of the 'const' qualifier, if any. + /// Retrieve the location of the 'const' qualifier. SourceLocation getConstQualifierLoc() const { - return SourceLocation::getFromRawEncoding(ConstQualifierLoc); + assert(MethodQualifiers); + return MethodQualifiers->getConstSpecLoc(); } - /// Retrieve the location of the 'volatile' qualifier, if any. + /// Retrieve the location of the 'volatile' qualifier. SourceLocation getVolatileQualifierLoc() const { - return SourceLocation::getFromRawEncoding(VolatileQualifierLoc); + assert(MethodQualifiers); + return MethodQualifiers->getVolatileSpecLoc(); } - /// Retrieve the location of the 'restrict' qualifier, if any. + /// Retrieve the location of the 'restrict' qualifier. SourceLocation getRestrictQualifierLoc() const { - return SourceLocation::getFromRawEncoding(RestrictQualifierLoc); + assert(MethodQualifiers); + return MethodQualifiers->getRestrictSpecLoc(); } /// Retrieve the location of the 'mutable' qualifier, if any. @@ -1574,12 +1588,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 +1603,8 @@ SourceLocation LocalRangeEnd, Declarator &TheDeclarator, TypeResult TrailingReturnType = - TypeResult()); + TypeResult(), + DeclSpec *MethodQualifiers = 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 @@ -6072,9 +6072,6 @@ DeclSpec DS(AttrFactory); bool RefQualifierIsLValueRef = true; SourceLocation RefQualifierLoc; - SourceLocation ConstQualifierLoc; - SourceLocation VolatileQualifierLoc; - SourceLocation RestrictQualifierLoc; ExceptionSpecificationType ESpecType = EST_None; SourceRange ESpecRange; SmallVector DynamicExceptions; @@ -6137,9 +6134,6 @@ })); if (!DS.getSourceRange().getEnd().isInvalid()) { EndLoc = DS.getSourceRange().getEnd(); - ConstQualifierLoc = DS.getConstSpecLoc(); - VolatileQualifierLoc = DS.getVolatileSpecLoc(); - RestrictQualifierLoc = DS.getRestrictSpecLoc(); } // Parse ref-qualifier[opt]. @@ -6239,15 +6233,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,22 @@ 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, StringRef FixItName, + SourceLocation SpecLoc) { FixItHint Insertion; - if (DS.getTypeQualifiers() & TypeQual) { - if (!(Function.TypeQuals & TypeQual)) { - std::string Name(FixItName); - Name += " "; - Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name); - Function.TypeQuals |= TypeQual; - *QualifierLoc = SpecLoc.getRawEncoding(); - } - Diag(SpecLoc, diag::err_declspec_after_virtspec) + auto &MQ = Function.getOrCreateMethodQualifiers(); + if (!(MQ.getTypeQualifiers() & TypeQual)) { + std::string Name(FixItName.data()); + Name += " "; + Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name); + MQ.SetTypeQual(TypeQual, SpecLoc); + } + Diag(SpecLoc, diag::err_declspec_after_virtspec) << FixItName << VirtSpecifiers::getSpecifierName(VS.getLastSpecifier()) - << FixItHint::CreateRemoval(SpecLoc) - << Insertion; - } + << 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); + DS.forEachQualifier(DeclSpecCheck); } // 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,12 +1206,8 @@ /*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, @@ -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, 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 *MethodQualifiers) { + assert(!(MethodQualifiers && MethodQualifiers->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,21 @@ I.Fun.HasTrailingReturnType = TrailingReturnType.isUsable() || TrailingReturnType.isInvalid(); I.Fun.TrailingReturnType = TrailingReturnType.get(); + I.Fun.MethodQualifiers = nullptr; + I.Fun.QualAttrFactory = nullptr; + + if (MethodQualifiers && (MethodQualifiers->getTypeQualifiers() || + MethodQualifiers->getAttributes().size())) { + auto &attrs = MethodQualifiers->getAttributes(); + I.Fun.MethodQualifiers = new DeclSpec(attrs.getPool().getFactory()); + MethodQualifiers->forEachCVRUQualifier( + [&](DeclSpec::TQ TypeQual, StringRef PrintName, SourceLocation SL) { + I.Fun.MethodQualifiers->SetTypeQual(TypeQual, SL); + }); + I.Fun.MethodQualifiers->getAttributes().takeAllFrom(attrs); + I.Fun.MethodQualifiers->getAttributePool().takeAllFrom(attrs.getPool()); + } - assert(I.Fun.TypeQuals == TypeQuals && "bitfield overflow"); assert(I.Fun.ExceptionSpecType == ESpecType && "bitfield overflow"); // new[] a parameter array if needed. @@ -403,6 +407,24 @@ (getName().getKind() == UnqualifiedIdKind::IK_DestructorName); } +void DeclSpec::forEachCVRUQualifier( + llvm::function_ref Handle) { + if (TypeQualifiers & TQ_const) + Handle(TQ_const, "const", TQ_constLoc); + if (TypeQualifiers & TQ_volatile) + Handle(TQ_volatile, "volatile", TQ_volatileLoc); + if (TypeQualifiers & TQ_restrict) + Handle(TQ_restrict, "restrict", TQ_restrictLoc); + if (TypeQualifiers & TQ_unaligned) + Handle(TQ_unaligned, "unaligned", TQ_unalignedLoc); +} + +void DeclSpec::forEachQualifier( + llvm::function_ref Handle) { + forEachCVRUQualifier(Handle); + // FIXME: Add code below to iterate through the attributes and call Handle. +} + bool DeclSpec::hasTagDefinition() const { if (!TypeSpecOwned) return false; @@ -862,6 +884,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,12 @@ } DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); - if (FTI.TypeQuals != 0) { - if (FTI.TypeQuals & Qualifiers::Const) - Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) - << "const" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & Qualifiers::Volatile) - Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) - << "volatile" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & Qualifiers::Restrict) - Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) - << "restrict" << SourceRange(D.getIdentifierLoc()); + if (FTI.MethodQualifiers) { + FTI.MethodQualifiers->forEachQualifier( + [&](DeclSpec::TQ TypeQual, StringRef QualName, SourceLocation SL) { + Diag(SL, diag::err_invalid_qualified_constructor) + << QualName << SourceRange(SL); + }); D.setInvalidType(); } @@ -8361,16 +8357,12 @@ } DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); - if (FTI.TypeQuals != 0 && !D.isInvalidType()) { - if (FTI.TypeQuals & Qualifiers::Const) - Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) - << "const" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & Qualifiers::Volatile) - Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) - << "volatile" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & Qualifiers::Restrict) - Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) - << "restrict" << SourceRange(D.getIdentifierLoc()); + if (FTI.MethodQualifiers && !D.isInvalidType()) { + FTI.MethodQualifiers->forEachQualifier( + [&](DeclSpec::TQ TypeQual, StringRef QualName, SourceLocation SL) { + Diag(SL, diag::err_invalid_qualified_destructor) + << QualName << SourceRange(SL); + }); D.setInvalidType(); } Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -884,8 +884,10 @@ // 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.getOrCreateMethodQualifiers().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, @@ -737,8 +733,7 @@ /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, - /*DeclsInPrototype=*/None, - loc, loc, declarator)); + /*DeclsInPrototype=*/None, loc, loc, declarator)); // For consistency, make sure the state still has us as processing // the decl spec. @@ -4460,7 +4455,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.MethodQualifiers || FTI.hasRefQualifier(); // Check for auto functions and trailing return type and adjust the // return type accordingly. @@ -4698,7 +4693,9 @@ EPI.ExtInfo = EI; EPI.Variadic = FTI.isVariadic; EPI.HasTrailingReturn = FTI.hasTrailingReturnType(); - EPI.TypeQuals.addCVRUQualifiers(FTI.TypeQuals); + EPI.TypeQuals.addCVRUQualifiers( + FTI.MethodQualifiers ? FTI.MethodQualifiers->getTypeQualifiers() + : 0); EPI.RefQualifier = !FTI.hasRefQualifier()? RQ_None : FTI.RefQualifierIsLValueRef? RQ_LValue : RQ_RValue; @@ -5024,14 +5021,15 @@ SmallVector RemovalLocs; const DeclaratorChunk &Chunk = D.getTypeObject(I); assert(Chunk.Kind == DeclaratorChunk::Function); + if (Chunk.Fun.hasRefQualifier()) RemovalLocs.push_back(Chunk.Fun.getRefQualifierLoc()); - if (Chunk.Fun.TypeQuals & Qualifiers::Const) - RemovalLocs.push_back(Chunk.Fun.getConstQualifierLoc()); - if (Chunk.Fun.TypeQuals & Qualifiers::Volatile) - RemovalLocs.push_back(Chunk.Fun.getVolatileQualifierLoc()); - if (Chunk.Fun.TypeQuals & Qualifiers::Restrict) - RemovalLocs.push_back(Chunk.Fun.getRestrictQualifierLoc()); + + if (Chunk.Fun.MethodQualifiers) + Chunk.Fun.MethodQualifiers->forEachQualifier( + [&](DeclSpec::TQ TypeQual, StringRef QualName, + SourceLocation SL) { RemovalLocs.push_back(SL); }); + if (!RemovalLocs.empty()) { llvm::sort(RemovalLocs, BeforeThanCompare(S.getSourceManager()));