Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -2586,14 +2586,10 @@ } } - if (Result->isOpaquePointerTy()) { - unsigned AddrSpace; - if (parseOptionalAddrSpace(AddrSpace)) - return true; - Result = PointerType::get(getContext(), AddrSpace); - } - - // parse the type suffixes. + // Parse the type suffixes. Opaque pointers spelled as 'ptr' should not end + // with a '*', but need to check the flag before the loop to support + // '--force-opaque-pointers'. + bool IsSpelledPtr = Result->isOpaquePointerTy(); while (true) { switch (Lex.getKind()) { // End of type. @@ -2608,7 +2604,7 @@ return tokError("basic block pointers are invalid"); if (Result->isVoidTy()) return tokError("pointers to void are invalid - use i8* instead"); - if (Result->isOpaquePointerTy()) + if (IsSpelledPtr) return tokError("ptr* is invalid - use ptr instead"); if (!PointerType::isValidElementType(Result)) return tokError("pointer to this type is invalid"); @@ -2625,7 +2621,9 @@ if (!PointerType::isValidElementType(Result)) return tokError("pointer to this type is invalid"); unsigned AddrSpace; - if (parseOptionalAddrSpace(AddrSpace) || + if (parseOptionalAddrSpace(AddrSpace)) + return true; + if (!IsSpelledPtr && parseToken(lltok::star, "expected '*' in address space")) return true; Index: llvm/test/Other/force-opaque-ptrs.ll =================================================================== --- llvm/test/Other/force-opaque-ptrs.ll +++ llvm/test/Other/force-opaque-ptrs.ll @@ -32,3 +32,9 @@ @g.fwd = global i32 0 declare void @fn.fwd(i32) + +define void @f2(i32** %p) { +; CHECK-LABEL: define {{[^@]+}}@f2( +; CHECK-SAME: ptr {{%.*}}) { + unreachable +}